Laden...

Profil von rdilse

myCSharp.de - Member Mitglied seit
rdilse
myCSharp.de - Member
3
Themen
11
Beiträge
Studium der Visuellen Kommunikation und Wirtschaftsinformatik. Seit 1983 tätig als Softwareentwickler, Berater, Projektleiter sowie in zahlreichen Funktionen in Management und Vertrieb für namhafte IT-Unternehmensberatungen. Seit September 2020 im Ruhestand und freiberuflich als Berater tätig.
Dabei seit
16.03.2025
Letzte Aktivität
vor 2 Monaten
Beruf
Senior Expert
Herkunft
Bayern
Erstellt vor 2 Monaten

Problem gelöst!

Nachdem ich das eigene Root-Zertifikat mit der Management-Konsole unter "Vertrauenswürdige Stammzertifizierungsstellen" und das Intermediate-Zertifikat unter "Zwischenzertifizierungsstellen" eingetragen habe, klappt alles wie geplant.

Erstellt vor 2 Monaten

Wenn der C#-Client auf TLS1.2 (statt 1.3) umgestellt wird, meldet der PHP-Server statt FAILED jetzt GENEROUS.

Bei Java und Python ist es unerheblich, welche TLS-Version eingestellt ist, es wird immer SUCCESS gemeldet.

Ich habe die Verbindungsdaten sowohl vom C#-Client als auch vom Java-Client und vom Python-Client mit Wireshark verglichen (jeweils mit TLS1.2). Bei allen Clients wurden beim Server 2 Zertifikate empfangen, nämlich das Client-Zertifikat und das Intermediate-Zertifikat. Daher ist für mich nicht verständlich, warum sich C# anders verhält als Python oder Java.

Erstellt vor 2 Monaten

Der c# Client bekommt nur eine Verbindung zum Server, wenn in Apache

SSLVerifyClient optional_no_ca

definiert ist. Bei SSLVerifyClient optional oder SSLVerifyClient required wird die Verbindung abgelehnt.

Erstellt vor 2 Monaten

Hier der vergleichbare Java-Client, der die gleiche P12-Datei mit Client-Zertifikat, Private Key und Intermediate-CA-Zertifikat nutzt wie das C#-Pendant.

Alles etwas umständlicher als in der C#-Welt.

Dieser Client verifiziert zusätzlich das Server-Zertifikat gegen das eigene root-Zertifikat.

import java.io.*;
import java.net.*;
import javax.net.ssl.*;
import java.util.*;
import java.security.*;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

public class Main {

    public static void main(String[] args)
    {
        try {
            String keyPassphrase = "xxxxx";

            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
            KeyStore keyStore = KeyStore.getInstance("PKCS12");
			
			// p12-Datei mit Chain aus Client-Zertifikat mit Private Key und Intermediate-CA-Zertifikat
            keyStore.load(new FileInputStream("C:\\Austausch\\SSLneu2\\client-chain.p12"), keyPassphrase.toCharArray());

			// zusätzlich Server-Zertifikat mit eigenem CA-Zertifikat verifizieren
            // 1. CA-Zertifikat aus PEM-Datei laden
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            FileInputStream fis = new FileInputStream("C:\\Austausch\\SSLneu2\\testrootca-crt.pem");
            X509Certificate caCert = (X509Certificate) cf.generateCertificate(fis);

            // 2. Neuen leeren KeyStore anlegen
            KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
            ks.load(null, null); // leer initialisieren
            ks.setCertificateEntry("myCA", caCert);

            // 3. TrustManagerFactory mit unserem KeyStore initialisieren
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(
            TrustManagerFactory.getDefaultAlgorithm());
            tmf.init(ks);

            // 4. Ersten TrustManager ziehen und akzeptierte Issuer ausgeben
            X509TrustManager tm = (X509TrustManager) tmf.getTrustManagers()[0];
            for (X509Certificate cert : tm.getAcceptedIssuers()) {
                System.out.println("Akzeptierte CA: " + cert.getSubjectDN());
            }

            keyManagerFactory.init(keyStore, keyPassphrase.toCharArray());
            KeyManager[] kms = keyManagerFactory.getKeyManagers();

			// Install the trust manager
            SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
            sslContext.init(kms, tmf.getTrustManagers(), new java.security.SecureRandom()); // nur das eigene CA Zertifikat akzeptieren
            HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
            HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostName, SSLSession session) {
                    return true;
                }
            });

            URL url;
            url = new URL("https://localhost/mbbsim/test4.php?params=Java");			// PHP Testmock

			String charset = "UTF-8";

			SSLParameters sslParameters = new SSLParameters();
			List sniHostNames = new ArrayList(1);
			sniHostNames.add(new SNIHostName(url.getHost()));
			sslParameters.setServerNames(sniHostNames);
			SSLSocketFactory wrappedSSLSocketFactory = new SSLSocketFactoryWrapper(sslContext.getSocketFactory(), sslParameters);

            HttpsURLConnection connection = (HttpsURLConnection)url.openConnection();
            connection.setRequestProperty("Accept-Charset", charset);
            InputStream response = connection.getInputStream();

            try (Scanner scanner = new Scanner(response)) {
                String responseBody = scanner.useDelimiter("\\A").next();
                System.out.println(responseBody);
            }
        }
        catch (java.net.MalformedURLException e)
        {
            System.out.println(e);
        }
        catch (java.security.NoSuchAlgorithmException e)
        {
            System.out.println(e);
        }
        catch (java.security.KeyManagementException e)
        {
            System.out.println(e);

        }
        catch (Exception e)
        {
            System.out.println("Fehler"+e);
        }


    }
}
Erstellt vor 2 Monaten

Hier das PHP Code-Snippet, das den Subject und den Issuer des Client-Zertifikats ausgibt sowie den Verify-Status ($_SERVER["SSL_CLIENT_VERIFY"]).

Der Verify-Status sollte SUCCESS enthalten.

<?php

	$methode = $_SERVER['REQUEST_METHOD'];
	$ausgabe = "";

if ($methode === 'GET') {
     // The request is using the GET method
	 
	$ausgabe = "PHP Test1 GET: ";

	 if (!empty($_REQUEST["params"])) {
		 $ausgabe .= " ".$_REQUEST["params"]."<br>\n";
		 
		 if (!empty($_SERVER["SSL_CLIENT_S_DN"])) $ausgabe .= " SSL_CLIENT_S_DN: ".$_SERVER["SSL_CLIENT_S_DN"]."<br>\n";
		 if (!empty($_SERVER["SSL_CLIENT_I_DN"])) $ausgabe .= " SSL_CLIENT_I_DN: ".$_SERVER["SSL_CLIENT_I_DN"]."<br>\n";
		 if (!empty($_SERVER["SSL_CLIENT_VERIFY"])) $ausgabe .= " SSL_CLIENT_VERIFY: ".$_SERVER["SSL_CLIENT_VERIFY"]."<br>\n";
	 
		 }
}

?>
<html>
<body>
menno
<?=$ausgabe?><br>
</body>
</html>
Erstellt vor 2 Monaten

Der Server (Apache / PHP) meldet: SSL_CLIENT_VERIFY: FAILED:unable to verify the first certificate

Im Apache ist das Root-CA-Zertifikat richtig eingetragen:

SSLCACertificateFile "conf/ssl.crt/testrootca-crt.pem"

Die Zertifikats-Kette besteht aus einem Client-Zertifikat und einem Intermediate-CA-Zertifikat. Das root-Zertifikat ist selbst erstellt und selbst signiert.

Bei einem vergleichbaren Java-Client sowie einem Python-Client kann der Server das erste Zertifikat erfolgreich verifizieren und PHP meldet: SSL_CLIENT_VERIFY: SUCCESS

Weder ChatGPT noch Claude Sonnet4 konnten eine brauchbare Lösung anbieten und bei Stack Overflow habe ich auch nichts gefunden. Wo habe ich was falsch gemacht?

        string certpath = "C:\\Austausch\\SSLneu2\\client-chain.p12";
// client-chain.p12 enthält das Client-Zertifikat und den Client-Private-Key 
// und das Intermediate-CA Zertifikat

        byte[] rawCert = File.ReadAllBytes(certpath);
        X509Certificate2Collection certificateCollection = X509CertificateLoader.LoadPkcs12Collection(
             rawCert,
            "xxxxx",
            X509KeyStorageFlags.Exportable
        );
	// Collection damit füllen:

        var handler = new HttpClientHandler();
        handler.ClientCertificateOptions = ClientCertificateOption.Manual;
        handler.ClientCertificates.AddRange(certificateCollection);

// hier dann der HTTPS Aufruf:

        using HttpClient client = new HttpClient(handler);
        string url = "https://localhost/mbbsim/test4.php?params=dotnet"; // Beispiel-API

        try
        {
            HttpResponseMessage response = await client.GetAsync(url);
            response.EnsureSuccessStatusCode(); // Exception, wenn der Statuscode nicht erfolgreich ist

            string responseBody = await response.Content.ReadAsStringAsync();
            Console.WriteLine(responseBody);
        }
	…
Erstellt vor 3 Monaten

Das Problem besteht darin, dass es die Bibliotheken nicht im .lib-Format gibt, sondern im .a-Format (für Linux), obwohl der Download explizit für Windows angeboten wird

Erstellt vor 3 Monaten

Ich möchte ein C++-Programm erstellen, das HTTP(S)-Zugriffe durchführen und  dafür möchte ich die cURL-Bibliothek verwenden.

ich habe cURL von der offiziellen Webseite als zip-File heruntergeladen und entpackt. Jetzt möchte ich cURL zu einem Projekt hinzufügen, aber alle Beschreibungen, die ich recherchiert habe, funktionieren nicht.

Ich verwende Visual Studio 2022 auf einem Windows 11 Laptop.

Wer kann mir Tipps geben?

Erstellt vor 9 Monaten

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);
Erstellt vor 9 Monaten

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