SSL/TLS-Zertifikate in C# herunterladen

SSL-TLS Zertifikate in C-Sharp downloadenIn diesem Artikel soll es darum gehen wie man SSL/TLS-Zertifikate beliebiger Server in C# herunterladen bzw. speichern kann. Zwar lassen sich Zertifikate heutzutage auch recht einfach aus dem Webbrowser heraus speichern, jedoch ist dies immer mit recht vielen Klicks verbunden. Und spätestens, wenn man Zertifikate von Mail-Servern, etc. speichern möchte, also Systemen die nicht direkt im Webbrowser angesprochen werden können, ist eine programmatische Lösung, wie in diesem Beitrag gezeigt, der einfachere Weg.

Insgesamt möchte ich heute zwei Varianten vorstellen. Eine Variante, die nur für HTTPS-Verbindungen funktioniert und eine Variante, die für sämtliche TCP-Verbindungen (also auch Mailserver, etc.) funktioniert.

HTTPS/SSL-Zertifikate in C# herunterladen

Die erste angesprochene Lösung funktioniert nur für HTTPS-Verbindungen und basiert auf der HttpWebRequest-Klasse, welche auch unter der WebClient-Klasse liegt. Erstellt man ein HttpWebRequest, kann man daraus ein Objekt vom Typ HttpWebResponse erhalten.

HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://google.com:443");
request.AllowAutoRedirect = false;
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
response.Close();
X509Certificate2 cert = new X509Certificate2(request.ServicePoint.Certificate);

Das Zertifikat wird zwar aus der request-Instanz entnommen, jedoch muss die Response mittels GetResponse()-Aufruf angefordert werden, damit die Anfrage an den Server gesendet wird. Denn ohne Anfrage, wird auch kein Zertifikat im request-Objekt abgelegt. Nach dem Ausführen des Requests, kann das Zertifikat der aus request.ServicePoint.Certificate entnommen werden. Als Objekt-Typ habe ich bewusst X509Certificate2 gewählt, da diese Klasse umfangreicher ist als die (alte) X509Certificate-Klasse.

SSL/TLS-Zertifikate von TCP-Verbindungen in C# speichern

Wie versprochen möchte ich noch eine zweite Variante vorstellen. Diese ist etwas flexibler als die bereits aufgezeigte Variante, jedoch auch etwas komplizierter im Fehlerhandling. So müssen wir hier ein eigenes RemoteCertificateValidationCallback anlegen, damit wir das Zertifikat in jedem Fall bekommen. Ohne dieses würde der Code z.B. eine Exception werfen, wenn das Zertifikat abgelaufen ist. Jedoch gerade in diesem Fall, mag man interessiert am Zertifikat sein, weshalb wir ein eigenes Callback anlegen und immer “true” zurückgeben, damit das Zertifikat in jedem Fall gezogen wird.

try
{
    X509Certificate2 cert = null;
    var client = new TcpClient("imap.gmail.com", 993);
    var certValidation = new RemoteCertificateValidationCallback(delegate (object snd, X509Certificate certificate,
                X509Chain chainLocal, SslPolicyErrors sslPolicyErrors)
    {
        return true; //Accept every certificate, even if it's invalid
    });

    // Create an SSL stream and takeover client's stream
    using (var sslStream = new SslStream(client.GetStream(), true, certValidation))
    {
        sslStream.AuthenticateAsClient("imap.gmail.com");
        var serverCertificate = sslStream.RemoteCertificate;
        cert = new X509Certificate2(serverCertificate);
    }
}
catch (Exception e) {
    //throw some fancy exception ;-)
}

Danach erstellen wir aus dem TcpClient-Stream einen SslStream und greifen über dessen RemoteCertificate-Eigenschaft das SSL/TLS-Zertifikat ab. Wie gesagt, diese Variante ist nicht ganz so schön wie die erste, dafür bietet sie jedoch die Möglichkeit Zertifikate für nahezu alle Arten von Server abzugreifen.

Raffi

Seit 2011 blogge ich hier über Programmierung, meine Software, schreibe Tutorials und versuche mein Wissen, so gut es geht, mit meinen Lesern zu teilen.

Hinterlasse einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Sie dient nur dem Spamschutz.