Laden...

Client-Authentifizierung mit Elliptic Curves-Zertifikat

Letzter Beitrag vor einem Monat 5 Posts 296 Views
Client-Authentifizierung mit Elliptic Curves-Zertifikat

Ich habe eine Anwendung, die einen REST-Webservice über https aufruft. Der Client authentifiziert sich dabei mit einem X509-Zertifikat.

Bislang wurde ein Zertifikat mit RSA-Schlüsseln verwendet und es hat wunderbar funktioniert.

Jetzt wurde das Zertifikat auf Elliptic Curves-Schlüssel umgestellt und ich bekomme den Aufruf nicht mehr zum Laufen, egal ob ich Zertifikat und Schlüssel im PEM-Format benutze oder ein Zertifikat im p12-Format einsetze, das sowohl Zertifikat als auch den privaten Schlüssel enthält.

Ich habe es sowohl mit der System.Security.Cryptography.X509Certificates.HttpClient-Klasse versucht als auch mit Bouncy Castle. Ich setze Visual Studio mit .NET Framework 4.8.1 ein.

Ich kann den Webservice problemlos von Python und von Java (mit Bouncy Castle) aufrufen, sowohl mit RSA- als auch mit Elliptic Curves-Zertifikat.

Wer kann mir ein Code-Snippet zukommen lassen? Im Internet finde ich nichts und das Snippet, das ich von ChatGPT erhalten habe, funktioniert nicht.

"Geht nicht" ist nicht wirklich eine Erklärung, bei der man aktive Hilfe erwarten kann. Wir haben keine Glaskugel.
Was geht denn nicht? Wie lautet die Fehlermeldung? Wie sieht Dein Code aus?


Die .NET Implementierung für ECDSA ist die ECDsa Klasse.

Laden kannst Du ein valides PFX-File via

X509Certificate2 cert = new("my-cert.pfx");
ECDsa key = cert.GetECDsaPrivateKey() ?? cert.GetECDsaPublicKey();

Willst Du das PEM laden brauchst Du

X509Certificate2 cert = new(Convert.FromBase64String(pem-string-hier));

// sowie
X509Certificate2 certWithKey = cert.CopyWithPrivateKey(dein-private-key-hier);

Danke für die Antwort und sorry für die fehlenden Informationen.

Hier der Code, der mit einem RSA-Zertifikat funktioniert:

using System;
using System.IO;
using System.Net.Http;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
namespace ConsoleApp2
{
   class Program
   {
       static String retvalue;
       static void Main(string[] args)
       {
           Console.WriteLine("https://localhost/mbbsim/test4.php?params=show mit SSL und Zertifikat aufgerufen");
           retvalue = new String(GetValue());
           Console.WriteLine(retvalue);
           Console.ReadKey();
       }
       static string GetValue()
       {
           var retstring = "";
           //string certpath = "C:\\temp\\CAItest\\signed.p12";
           string certpath = "C:\\Austausch\\SSL\\XXXXXX_Client_EXAM.p12";
           Console.WriteLine(certpath);
           X509Certificate2 certificate = new X509Certificate2(certpath, "David", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
           Console.WriteLine("neues X509certificate2 erzeugt");
           // Fehler in der Server-Zertifikatskette ignorieren
           var handler = new HttpClientHandler();
           Console.WriteLine("neuen HttpClientHandler angelegt");
           handler.ClientCertificates.Add(certificate);
           Console.WriteLine("certificate hinzugefügt");
           handler.ClientCertificateOptions = ClientCertificateOption.Manual;
           Console.WriteLine("ClientCertificateOption.Automatic definiert");
           handler.ServerCertificateCustomValidationCallback =
               (httpRequestMessage, cert, cetChain, policyErrors) =>
               {
                   return true;
               };
           Console.WriteLine("Callback eingerichtet");
           try
           {
               var client = new HttpClient(handler);
               Console.WriteLine("neues HttpClient Objekt erzeugt");
               var webRequest = new HttpRequestMessage(HttpMethod.Get, "https://localhost/mbbsim/test4.php?params=show");
               var response = client.Send(webRequest);
               var reader = new StreamReader(response.Content.ReadAsStream());
               retstring = reader.ReadToEnd();
           }
           catch (System.Net.Http.HttpRequestException e)
           {
               // Win32Exception: Die Anmeldeinformationen, die dem Paket übergeben wurden, wurden nicht erkannt
               retstring = "Fehler " + e.Message;
               if (e.InnerException != null)
                   Console.WriteLine("Inner exception: {0}", e.InnerException);
           }
           return retstring;
       }
   }
}  

Bei Verwendung des hier auskommentierten EC-Zertifikats "signed.p12" kommt es zur Exception mit der Info, dass die Anmeldeinformationen nicht erkannt wurden

Bitte das nächste Mal den Code in die Code-Tags packen; niemand will unformatierten Code lesen. Habs für Dich editiert.


handler.ClientCertificateOptions = ClientCertificateOption.Manual;
Console.WriteLine("ClientCertificateOption.Automatic definiert");

ist ein Fehler von Dir oder aufgrund von Try-and-Error vorgehen oder irgendwas generiert?

Korrekter und struktuiert müsste Dein Code so aussehen:

X509Certificate2 certificate = new(certpath);

HttpClientHandler handler = new ();
handler.ClientCertificates.Add(certificate);

using (HttpClient client = new (handler))
{
    try
    {
        HttpResponseMessage response = await client.GetAsync("https://localhost/mbbsim/test4.php?params=show");

        if (response.IsSuccessStatusCode)
        {
            string content = await response.Content.ReadAsStringAsync();
            Console.WriteLine("Antwort: " + content);
        }
        else
        {
            Console.WriteLine("Fehler: " + response.StatusCode);
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine("Exception: " + ex.Message);
    }
}

Wobei man den Client nur einmalig intialisieren soll, siehe Doku.


Welche Win32 Exception bekommst Du? Die 0x80004005? Bitte immer das Original posten.

Wenn es die 0x80004005 ist, dann sind dazu zwei weit verbreitete Fehler: die Anwendung kann nicht auf das Certs zugreifen (Pfad, Optionen..) oder das Cert is ungültig aka der Private Key fehlt.

Hab in einer meiner Anwendungen auch ECDsa und ich lade erfolgreich das Cert mit .NET 7 via

X509Certificate2 certificate = new();
byte[] rawCert = await File.ReadAllBytesAsync("my.p12", ct);
certificate.Import(rawCert, options.Password, X509KeyStorageFlags.PersistKeySet); 

Vielen herzlichen Dank für deine Hilfe!

Ich habe nur den Konstruktor geändert, damit läuft das kleine Programm sowohl mit RSA- als auch mit ECDsa-Zertifikat. Kleine Ursache, große Wirkung!

            byte[] rawCert = File.ReadAllBytes(certpath);
            X509Certificate2 certificate = new X509Certificate2(rawCert, "David", X509KeyStorageFlags.PersistKeySet);