Ich versuche, HTTP-Aufrufe an einen Server vorzunehmen, der eine bidirektionale SSL-Verbindung (Client-Authentifizierung) erfordert. Ich habe eine .p12-Datei, die mehr als ein Zertifikat und ein Passwort enthält. Die Anfrage wird unter Verwendung des Protokollpuffers serialisiert.Zwei-Wege-Authentifizierung mit HTTPClient
Mein erster Gedanke war, den Keystore zu den ClientCertificate-Eigenschaften des WebRequestHandler, der von dem HttpClient verwendet wird, hinzuzufügen. Ich habe den Schlüsselspeicher auch meinen vertrauenswürdigen Stammzertifizierungsstellen auf meinem Computer hinzugefügt.
Ich bekomme immer eine "konnte nicht SSL/Tls sicheren Kanal erstellen", wenn der PostAsync ausgeführt wird. Es gibt offensichtlich etwas, das ich falsch mache, aber ich bin hier ein wenig verloren.
Alle Hinweise würden geschätzt.
public void SendRequest()
{
try
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;
var handler = new WebRequestHandler();
// Certificate is located in bin/debug folder
var certificate = new X509Certificate2Collection();
certificate.Import("MY_KEYSTORE.p12", "PASSWORD", X509KeyStorageFlags.DefaultKeySet);
handler.ClientCertificates.AddRange(certificate);
handler.ServerCertificateValidationCallback = ValidateServerCertificate;
var client = new HttpClient(handler)
{
BaseAddress = new Uri("SERVER_URL")
};
client.DefaultRequestHeaders.Add("Accept", "application/x-protobuf");
client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/x-protobuf");
client.Timeout = new TimeSpan(0, 5, 0);
// Serialize protocol buffer payload
byte[] protoRequest;
using (var ms = new MemoryStream())
{
Serializer.Serialize(ms, MyPayloadObject());
protoRequest = ms.ToArray();
}
var result = await client.PostAsync("/resource", new ByteArrayContent(protoRequest));
if (!result.IsSuccessStatusCode)
{
var stringContent = result.Content.ReadAsStringAsync().Result;
if (stringContent != null)
{
Console.WriteLine("Request Content: " + stringContent);
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw;
}
}
private bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
if (sslPolicyErrors == SslPolicyErrors.None)
return true;
Console.WriteLine("Certificate error: {0}", sslPolicyErrors);
// Do not allow this client to communicate with unauthenticated servers.
return false;
}
EDIT
breche ich nicht einmal in ValidateServerCertificate. Sobald der PostAsync aufgerufen wird, wird eine Ausnahme ausgelöst. Protokoll ist definitiv TLS v1.
Client-Betriebssystem ist Windows 8.1. Server ist codiert in Java (nicht sicher, auf welchem Betriebssystem er läuft auf. Ich habe keinen Zugriff auf sie. Es ist eine Blackbox.)
Stacktrace
bei System.Net.HttpWebRequest.EndGetRequestStream (IAsyncResult asyncResult, TransportContext & Kontext) bei System.Net.Http.HttpClientHandler.GetRequestStreamCallback (IAsyncResult ar)
Es gibt keine innere Ausnahme.
Wer ist der Aussteller des Zertifikats, das in der .P12-Datei gespeichert ist? Glaubt der Server einem solchen Aussteller? –
Es wird vom Besitzer des Servers ausgegeben, mit dem ich eine Verbindung herstellen möchte (sie gaben mir die Datei). – Mathieu
Gibt ValidateServerCertificate 'true' oder' false' zurück? Kannst du einen Haltepunkt setzen und überprüfen? Falls es falsch zurückgibt, was ist der Wert von sslPolocyErrors? Versuchen Sie immer 'true' von der Methode zurückzugeben, nur um zu testen, ob dies das Problem löst? Vielleicht vertraut Ihr lokaler Computer dem Aussteller des Serverzertifikats nicht? –