Wie kann ich von einem Handheld-Gerät aus einen sicheren Kanal für SSL / TLS einrichten?

Ich versuche, eine REST-Methode von einem Handheld-Gerät (Windows CE / Compact Framework) mit folgendem Code aufzurufen:

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;
}

Die Werte, die an die Methode übergeben werden, sind:

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"

... aber ich kann die Verbindung nicht herstellen, weil "Sicherer Kanal für SSL / TLS konnte nicht hergestellt werden ... System.Net.Sockets.SocketException: Eine vorhandene Verbindung wurde vom Remote-Host zwangsweise geschlossen."

Was muss ich also tun, um einen sicheren Kanal für SSL / TLS einzurichten, damit die bestehende Verbindung vom emotional entfernten Host nicht so grob geschlossen wird?

Nebenbei bemerkt: Ich finde es ein bisschen rompecabezish, dass, als ich eine WebException abfing, dieser Code zum Absturz der App führte, aber als ich den catch-Block in eine generische Ausnahme änderte, schlug der Versuch, eine stille Verbindung herzustellen, fehl (der einzige Weg, wie ich Anhand der Protokolldatei konnte festgestellt werden, dass ein Problem aufgetreten ist.

Um genauer zu sein, mit dem WebException-Code im Catch-Block von HttpWebRequest SendHTTPRequestNoCredentials () wie folgt:

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));
}

... die App stürzte ab und die Protokolldatei enthielt diese Notizen (die gefürchtete 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)
    . . .

Mit dem generischen Ausnahmecode im Fangblock (wie oben in diesem Beitrag gezeigt) schien die App jedoch an einem sonnigen Sommersonntagmorgen durch den Park zu schlendern - keine Ausnahmebedingung, kein Absturz oder Anzeichen von Winter Was auch immer für eine Unzufriedenheit - aber die Protokolldatei enthüllt dies:

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)
    . . .

Ungeachtet des letzten interessanten Aspekts ist es wirklich wichtig, wie ich einen sicheren Kanal für SSL / TLS von einem Handheld-Gerät aus einrichten kann.

AKTUALISIERE

Ich habe den Code über eine "Sandbox" -App aufgerufen, die auf meinem PC ausgeführt wird, und erhalte eine ähnliche, wenn auch nicht identische Ausnahme. Dies ist, was es gefangen hat:

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

Basierend auf einigen Kommentaren hier und den dazugehörigen Links dachte ich, ich müsse dies in meinen Code einfügen:

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

... in irgendeinem Zusammenhang:

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

contentType) {ServicePointManager.ServerCertificateValidationCallback + = (Absender, Zertifikat, Kette, sslPolicyErrors) => true; WebRequest request = null; try {request = WebRequest.Create (uri);

... aber, obwohl dies eine .NET 3.5-Client-App ist, und demnach http: //msdn.microsoft.com/en-us/library/system.net.servicepointmanager.servercertificatevalidationcallbac

(v = vs.90) .aspx], ServerCertificateValidationCallback ist angeblich in 3.5 verfügbar, "ServerCertificateValidationCallback" ist für mich nicht verfügbar (ich erhalte "Symbol kann nicht aufgelöst werden"). Es scheint, dass dies in der System.Net-Assembly ist, aber Versuche, meinem Projekt einen Verweis auf System.Net hinzuzufügen, sind vergeblich, da über Verweise hinzufügen auf der Registerkarte .NET keine solche Assembly verfügbar ist. Die alphabetisch geordnete Liste reicht von "System.Messaging" bis "System.Net.Irda"

Ich denke, dieser Mangel liegt daran, dass dies ein funktionsarmes Compact Framework-Projekt ist.

Angenommen, dies ist der Fall (Compact Framework enthält kein ServerCertificateValidationCallback). Was ist die Problemumgehung für dieses Szenario? Wie kann ich meine Client-Handheld-App das selbstsignierte SSL-Zertifikat auf dem Server akzeptieren lassen (REST-App wird in einem lokalen Netzwerk ausgeführt)?

UPDATE 3

Sollte ich eine oder beide der folgenden Optionen in der Systemsteuerung> Programme> Windows-Funktionen aktivieren oder deaktivieren> Internetinformationsdienste> World Wide Web-Dienst> Sicherheit aktivieren / deaktivieren:

Client Certificate Mapping Authentication
IIS Client Certificate Mapping Authentication

?

UPDATE 4

Ich kann wie folgt auf ServicePoint zugreifen:

ServicePoint svcPoint = ServicePointManager.FindServicePoint(uri);

... aber tut mir das nicht gut Kann ich das Zertifikat so einstellen, dass es immer akzeptiert wird? IOW, was brauche ich hier:

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

Selbst mit diesem 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();
}

... ich bekomme noch folgendes:

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, der (leere) Konstruktor von TrustAllCertificatesPolicy ist wahrscheinlich umstritten, da er ausgegraut ist.

Antworten auf die Frage(4)

Ihre Antwort auf die Frage