Como posso estabelecer um canal seguro para SSL / TLS a partir de um dispositivo portátil?

Estou tentando chamar um método REST de um dispositivo portátil (estrutura Windows CE / Compact) com este código:

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

Os valores que estão sendo passados para o método são:

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"

... mas não consigo fazer a conexão porque "Não foi possível estabelecer um canal seguro para SSL / TLS ... System.Net.Sockets.SocketException: uma conexão existente foi forçada a ser fechada pelo host remoto"

Então, o que devo fazer para estabelecer um canal seguro para SSL / TLS, para que a conexão existente não seja tão rudemente fechada pelo host emocionalmente remoto?

Bem-vindo ao Nebenbei: acho um pouco estranho que, quando eu estava capturando uma WebException, esse código estava causando o travamento do aplicativo, mas quando mudei o bloco de captura para uma exceção genérica, a tentativa de conectar-se silenciosamente (a única maneira que pude dizer que havia um problema estava olhando para o arquivo de log).

Para ser mais específico, com o código WebException no bloco de captura do HttpWebRequest SendHTTPRequestNoCredentials (), da seguinte maneira:

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

... o aplicativo travou e o arquivo de log continha essas notas post mortem (o temido 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)
    . . .

No entanto, com o código de exceção genérico no bloco de captura (como mostrado na parte superior deste post), o aplicativo parecia estar passeando pelo parque em uma manhã ensolarada de domingo de verão - nenhuma mensagem de exceção ou falha ou sinal de qualquer descontentamento invernal qualquer que seja - mas o arquivo de log revela isso:

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

Não obstante esse último detalhe interessante, o que realmente importa é: Como posso estabelecer um canal seguro para SSL / TLS a partir de um dispositivo portátil?

ATUALIZAR

Liguei para o código de um aplicativo "sandbox" em execução no meu PC e recebo uma exceção semelhante, embora não idêntica. Isto é o que ele pegou:

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)
. . .
ATUALIZAÇÃO 2

Com base em alguns dos comentários aqui e nos links que os acompanham, eu pensei que precisava adicionar isso ao meu código:

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

... em algum contexto:

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

contentType) {ServicePointManager.ServerCertificateValidationCallback + = (remetente, certificado, cadeia, sslPolicyErrors) => true; Solicitação WebRequest = null; tente {request = WebRequest.Create (uri);

... mas, embora este seja um aplicativo cliente do .NET 3.5 e, de acordo com isso [http://msdn.microsoft.com/en-us/library/system.net.servicepointmanager.servercertificatevalidationcallback

(v = vs.90) .aspx], ServerCertificateValidationCallback está supostamente disponível na versão 3.5, "ServerCertificateValidationCallback" não está disponível para mim (recebo "não consigo resolver o símbolo"). Parece que isso está no assembly System.Net, mas as tentativas de adicionar uma referência ao System.Net ao meu projeto são inúteis, pois não existe um assembly disponível via Add References na guia .NET. A lista ordenada alfabeticamente vai de "System.Messaging" para "System.Net.Irda"

Eu acho que essa falta é porque esse é um projeto do Compact Framework com poucos recursos.

Supondo que seja assim (o Compact Framework não contém ServerCertificateValidationCallback), qual é a solução alternativa para esse cenário? Como posso meu aplicativo portátil cliente aceitar o certificado SSL autoassinado no servidor (aplicativo REST em execução em uma rede local)?

ATUALIZAÇÃO 3

Devo marcar / marcar um ou os dois itens abaixo em Painel de Controle> Programas> Ativar ou desativar recursos do Windows> Serviços de Informações da Internet> Serviço da World Wide Web> Segurança:

Client Certificate Mapping Authentication
IIS Client Certificate Mapping Authentication

?

ATUALIZAÇÃO 4

Eu posso acessar o ServicePoint, assim:

ServicePoint svcPoint = ServicePointManager.FindServicePoint(uri);

... mas isso me faz bem. Posso definir o certificado para algo que será o equivalente a sempre aceitá-lo. IOW, o que eu preciso aqui:

ServicePoint svcPoint = ServicePointManager.FindServicePoint(uri);
svcPoint.Certificate = ???
ATUALIZAÇÃO 5

Mesmo com este código:

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

... Eu ainda entendo isso:

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, o construtor TrustAllCertificatesPolicy (vazio) provavelmente é discutível, pois está acinzentado.