How can I establish a secure channel for SSL/TLS from a handheld device?
Asked Answered
B

2

5

I am trying to call a REST method from a handheld device (Windows CE / Compact framework) with this code:

public static HttpWebRequest SendHTTPRequestNoCredentials(string uri, HttpMethods method, string data, string contentType)
{
    ExceptionLoggingService.Instance.WriteLog("Reached 
fileXferREST.SendHTTPRequestNoCredentials");
    WebRequest request = null;
    try
    {
        request = WebRequest.Create(uri);
        request.Method = Enum.ToObject(typeof(HttpMethods), method).ToString();
        request.ContentType = contentType;
        ((HttpWebRequest)request).Accept = contentType;
        ((HttpWebRequest)request).KeepAlive = false;
        ((HttpWebRequest)request).ProtocolVersion = HttpVersion.Version10;

        if (method != HttpMethods.GET && method != HttpMethods.DELETE)
        {
            byte[] arrData = Encoding.UTF8.GetBytes(data);
            request.ContentLength = arrData.Length;
            using (Stream oS = request.GetRequestStream())
            {
                oS.Write(arrData, 0, arrData.Length);
            }
        }
        else
        {
            request.ContentLength = 0;
        }
    }
    catch (Exception ex)
    {
        String msgInnerExAndStackTrace = String.Format(
                "{0}; Inner Ex: {1}; Stack Trace: {2}", ex.Message, ex.InnerException, 
ex.StackTrace);
        ExceptionLoggingService.Instance.WriteLog(String.Format("From 
FileXferREST.SendHTTPRequestNoCredentials(): {0}", msgInnerExAndStackTrace));
    }
    return request as HttpWebRequest;
}

The vals being passed to the method are:

uri: "https://seastore.nrbq.ad/ggr.web/api/inventory/sendXML/duckbill/platypus/INV_3_20090313214959000.xml"
HttpMethods: HttpMethods.POST
data: [ some xml ]
contentType: "application/xml"

...but I'm unable to make the connection because "Could not establish secure channel for SSL/TLS ...System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host"

So what must I do to establish a secure channel for SSL/TLS, so that the existing connection is not so rudely closed by the emotionally remote host?

Nebenbei bemerkt: I find it a bit rompecabezish that when I was catching a WebException, this code was causing the app to crash, but when I changed the catch block to a generic exception, the attempt to connect silently failed (the only way I could tell there was a problem was by looking at the log file).

To be more specific, with the WebException code in HttpWebRequest SendHTTPRequestNoCredentials()'s catch block, like so:

catch (WebException webex)
{
    HttpWebResponse hwr = (HttpWebResponse)webex.Response;
    HttpStatusCode hsc = hwr.StatusCode;
    String webExMsgAndStatusCode = String.Format("{0} Status code == {1}", webex.Message, 
hsc.ToString());
    ExceptionLoggingService.Instance.WriteLog(String.Format("From 
FileXferREST.SendHTTPRequestNoCredentials: {0}", webExMsgAndStatusCode));
}

...the app crashed and the log file held these post mortem notes (the dreaded NRE!):

Date: 3/13/2009 11:40:15 PM
Message: Reached FileXferREST.SendHTTPRequestNoCredentials

Date: 3/13/2009 11:40:31 PM
Message: From frmMain.SendInventories: NullReferenceException; Inner Ex: ; Stack Trace:    at 
HHS.FileXferREST.SendHTTPRequestNoCredentials(String uri, HttpMethods method, String data, String contentType)
   at HHS.FileXferREST.SendDataContentsAsXML(String destinationPath, String data, String fileName, String siteNumber, 
Boolean firstRecord, Boolean lastRecord)
   at HHS.frmMain.SendInventories()
   at HHS.frmMain.menuItemSEND_Inventories_Click(Object sender, EventArgs e)
    . . .

However, with the generic Exception code in the catch block (as shown at the top of this post), the app seemed to be strolling through the park on a sunny summer Sunday morn -- no exception message or crash or sign of any wintery discontent whatsoever -- but the log file reveals this:

Date: 3/13/2009 11:54:52 PM
Message: Reached FileXferREST.SendHTTPRequestNoCredentials

Date: 3/13/2009 11:54:54 PM
Message: From FileXferREST.SendHTTPRequestNoCredentials(): Could not establish secure channel for SSL/TLS; Inner Ex: 
System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host
   at System.Net.Sockets.Socket.ReceiveNoCheck(Byte[] buffer, Int32 index, Int32 request, SocketFlags socketFlags)
   at System.Net.Sockets.Socket.Receive(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags)
   at System.Net.Connection.System.Net.ISslDataTransport.Receive(Byte[] buffer, Int32 offset, Int32 size)
   at System.Net.SslConnectionState.ClientSideHandshake()
   at System.Net.SslConnectionState.PerformClientHandShake()
   at System.Net.Connection.connect(Object ignored)
   at System.Threading.ThreadPool.WorkItem.doWork(Object o)
   at System.Threading.Timer.ring()
; Stack Trace:    at System.Net.HttpWebRequest.finishGetRequestStream()
   at System.Net.HttpWebRequest.GetRequestStream()
   at HHS.FileXferREST.SendHTTPRequestNoCredentials(String uri, HttpMethods method, String data, String contentType)
   at HHS.FileXferREST.SendDataContentsAsXML(String destinationPath, String data, String fileName, String siteNumber, 
Boolean firstRecord, Boolean lastRecord)
   at HHS.frmMain.SendInventories()
   at HHS.frmMain.menuItemSEND_Inventories_Click(Object sender, EventArgs e)
    . . .

Notwithstanding that last interesting tidbit, what really matters is: How can I establish a secure channel for SSL/TLS from a handheld device?

UPDATE

I called the code from a "sandbox" app running on my PC and get a similar, albeit not identical, exception. This is what it caught:

Message: From SendHTTPRequestNoCredentials(): The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.; Inner Ex: System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.
   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)
   at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
. . .

UPDATE 2

Based on some of the comments here, and the links that accompany them, I was thinking I needed to add this within my code:

        ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;

...in some context:

    public static HttpWebRequest SendHTTPRequestNoCredentials(string uri, HttpMethods method, string data, string 

contentType) { ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true; WebRequest request = null; try { request = WebRequest.Create(uri);

...but, although this is a .NET 3.5 client app, and, according to this [http://msdn.microsoft.com/en-us/library/system.net.servicepointmanager.servercertificatevalidationcallback

(v=vs.90).aspx], ServerCertificateValidationCallback is supposedly available in 3.5, "ServerCertificateValidationCallback" is not available to me (I get "cannot resolve symbol"). It seems this is in the System.Net assembly, but attempts to add a reference to System.Net to my project are futile, as there is no such assembly available via Add References on the .NET tab. The alphabetically-ordered list goes from "System.Messaging" to "System.Net.Irda"

I reckon this lack is because this is a feature-poor Compact Framework project.

Assuming this is so (Compact Framework does not contain ServerCertificateValidationCallback), what is the workaround for this scenario? How can I have my client handheld app accept the self-signed ssl certificate on the server (REST app running on a local network)?

UPDATE 3

Should I check/tick either or both of the following in Control Panel > Programs > Turn Windows features on or off > Internet Information Services > World Wide Web Service > Security:

Client Certificate Mapping Authentication
IIS Client Certificate Mapping Authentication

?

UPDATE 4

I can access ServicePoint, like so:

ServicePoint svcPoint = ServicePointManager.FindServicePoint(uri);

...but does this do me any good. Can I set the Certificate to something that will be the equivalent of always accepting it. IOW, what do I need here:

ServicePoint svcPoint = ServicePointManager.FindServicePoint(uri);
svcPoint.Certificate = ???

UPDATE 5

Even with this code:

namespace HHS
{
    using System.Net;
    using System.Security.Cryptography.X509Certificates;

    class TrustAllCertificatesPolicy : ICertificatePolicy
    {
        public TrustAllCertificatesPolicy()
        {
        }

        public bool CheckValidationResult(ServicePoint sp, X509Certificate cert, WebRequest req, int problem)
        {
            return true;
        }
    }
}

private void frmMain_Load(object sender, EventArgs e)
{
    System.Net.ServicePointManager.CertificatePolicy = new TrustAllCertificatesPolicy();
}

...I still get this:

Message: Reached FileXferREST.SendHTTPRequestNoCredentials

Date: 3/18/2009 11:41:09 PM
Message: From FileXferREST.SendHTTPRequestNoCredentials(): Could not establish secure channel for SSL/TLS; Inner Ex: System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host
   at System.Net.Sockets.Socket.ReceiveNoCheck(Byte[] buffer, Int32 index, Int32 request, SocketFlags socketFlags)
   at System.Net.Sockets.Socket.Receive(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags)
   at System.Net.Connection.System.Net.ISslDataTransport.Receive(Byte[] buffer, Int32 offset, Int32 size)
   at System.Net.SslConnectionState.ClientSideHandshake()
   at System.Net.SslConnectionState.PerformClientHandShake()
   at System.Net.Connection.connect(Object ignored)
   at System.Threading.ThreadPool.WorkItem.doWork(Object o)
   at System.Threading.Timer.ring()
; Stack Trace:    at System.Net.HttpWebRequest.finishGetRequestStream()
   at System.Net.HttpWebRequest.GetRequestStream()
   at HHS.FileXferREST.SendHTTPRequestNoCredentials(String uri, HttpMethods method, String data, String contentType)
. . .

BTW, TrustAllCertificatesPolicy's (empty) constructor is probably moot, as it is grayed out.

Barden answered 24/12, 2014 at 22:31 Comment(14)
Just from skimming, it sounds like you’re doing it right; it appears to me to be some sort of networking problem or problem on the server. Maybe a firewall or something.Notochord
Does your web server have an "official" (that is, not self-signed) SSL certificate installed?Dentition
I doubt it, but if it does, what would that change? If it is self-signed (I think it is), what would that mean, as relates to this issue? If you respond, I'll ask the cats who set it up whether it has a self-signed or "official" SSL certificate...Barden
The client will check if it trusts the server certificate by checking the certification path against the certificates in the devices' certificate store. If the device does not have a matching certificate installed (which is likely the case with self-signed server certificates) it will not trust the server certificate. From the sound of it, this is what is happening.Brew
You might try to bypass certificate validation on the client to verify that it is a cert issue. See this question.Horologist
@mikez: How would I "try to bypass certificate validation on the client"? Isn't that what I'm doing now (by not doing anything about it (since I didn't know such a thing might be required))?Barden
@B.ClayShannon WebRequest handles SSL for you. You bypass validation by proving a custom validation handler that just validates everything. This seems to be a standard troubleshooting technique.Horologist
@mikez: Okay, thanks, I'll czech that out Monday. If that can be done, I might just leave that there permanently.Barden
Verified today that the server has/uses a self-signed certificate.Barden
@CaptainJackSparrow: Sorry, I have no clue now; this was from three years ago.Barden
Do you can use khalidabuhakmeh.com/… ?Unbalance
@Unbalance Thanks for the suggestion; but I am no longer programming, so the answer is "no."Barden
@B.ClayShannon I have run into the exact same problem as yours and I have tried all the steps that you have mentioned in this thread without luck. Do you recall if/how you resolved this issue?Mossbunker
@amindomeniko: Sorry, I don't recall, it's too long ago. Perhaps never resolved, or I probably would have made a final update or created an answer.Barden
I
10

The .NET Compact Framework does not have ServerCertificateValidationCallback.
What you could do is to set a CertificatePolicy class to validate the certificate.

public class TrustAllCertificatePolicy : ICertificatePolicy
{
  public TrustAllCertificatePolicy()
  {
  }

  public bool CheckValidationResult(ServicePoint sp, X509Certificate cert, WebRequest req, int problem)
  {
    return true;
  }
}

...

System.Net.ServicePointManager.CertificatePolicy = new TrustAllCertificatePolicy();

See this link for more information.

Implacable answered 29/12, 2014 at 20:2 Comment(3)
That is a new problem. This time it's the server refusing the connection. Debug to get more information. Does the server require credentials or a certificate from the client? Is the server properly configured? Etc.Implacable
No, it's the same problem that provoked the question in the first place.Barden
Even if this works do not use it as it makes the point of using HTTPS irrelevant - it will be liability for enterprise or secure projects. You are basically saying yes for all certs including faked ones.Ulloa
U
0

Look at my answer Here

In a nutshell certificate management and security is not implemented well in CE and you will need to create your own web request object from Microsofts object. More details can be found at this link http://labs.rebex.net/HTTPS

Ulloa answered 19/1, 2017 at 3:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.