Akzeptieren aller SSL-Zertifikate

Hi Leute,

ich schreibe momentan an einem Test-Client für XMPP in Java. Es geht darum, den XMPP-Server openFire zu fuzzen. Mehr dazu in diesem Thread.

Folgender Code ist erstmal sehr primitiv, da ich erstmal versuche, das Protokoll nachzuvollziehen. Ich hoffe ihr seht mir das nach.

Code:
String host = "192.168.60.164";
int port = 5222;
Socket socket = new Socket(host, port);
PrintWriter writer = new PrintWriter(socket.getOutputStream());
InputStreamReader reader = new InputStreamReader(socket.getInputStream());

String header = "<stream:stream version='1.0' xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:client' to='localhost' xmlns:xml='http://www.w3.org/XML/1998/namespace'>";

// ############################################################################################################################################
// STARTTLS-REQUEST
StringBuilder msg = new StringBuilder();
msg.append(header + "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>");
writer.write(msg.toString());
writer.flush();
System.out.println("-> " + msg.toString());

// Wait for Response
Thread.sleep(500);

// Response
int rec;
System.out.print("<- ");
while(reader.ready()) {
    rec = reader.read();
    System.out.print((char)rec);
}
System.out.println();

// ############################################################################################################################################
// WRAP SOCKET WITH SSL
SSLSocket sslSocket = (SSLSocket) ((SSLSocketFactory) SSLSocketFactory.getDefault()).createSocket(socket, host, port, true);
reader = new InputStreamReader(sslSocket.getInputStream());
OutputStream out = sslSocket.getOutputStream();
msg = new StringBuilder();
String username = "testuser1@localhost";
String password = "test";
String userPass = "\0" + username + "\0" + password;
String userPassBase64 = new BASE64Encoder().encode(userPass.getBytes());
msg.append(header + "<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>" + userPassBase64 + "</auth>");
out.write(msg.toString().getBytes());
writer.flush();
System.out.println("-> " + msg.toString());

// Wait for Response
Thread.sleep(500);

// Response
System.out.print("<- ");
while(reader.ready()) {
    rec = reader.read();
    System.out.print((char)rec);
}
System.out.println();

-> <stream:stream version='1.0' xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:client' to='localhost' xmlns:xml='http://www.w3.org/XML/1998/namespace'><starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>

<- <?xml version='1.0' encoding='UTF-8'?><stream:stream xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:client" from="localhost" id="cecbddc2" xml:lang="en" version="1.0"><stream:features><starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"></starttls><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>DIGEST-MD5</mechanism><mechanism>PLAIN</mechanism><mechanism>ANONYMOUS</mechanism><mechanism>CRAM-MD5</mechanism></mechanisms><compression xmlns="http://jabber.org/features/compress"><method>zlib</method></compression><auth xmlns="http://jabber.org/features/iq-auth"/><register xmlns="http://jabber.org/features/iq-register"/></stream:features><proceed xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>

-> <stream:stream version='1.0' xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:client' to='localhost' xmlns:xml='http://www.w3.org/XML/1998/namespace'><auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>AHRlc3R1c2VyMUBsb2NhbGhvc3QAdGVzdA==</auth>

<-

Nach dem ersten Request kommen also die unterstützten Mechanismen. Sobald ich aber versuche, die SSL-Verbindung aufzubauen, kommt keine Antwort mehr vom Server.

Was ich bisher herausfinden konnte: Anscheinend liegt es daran, dass das Zertifikat meines Servers von mir selbst signiert ist. Es wurde automatisch bei der Installation von openFire generiert. Ich hab also nach einer Anleitung alle Zertifikate (nur für Tests - keine Angst :wink:) akzeptiert. Allerdings wird in dieser Anleitung von HTTPS ausgegangen.

Meine Fragen:
1. Wie kann ich alle Zertifikate (egal welche TCP-Verbindung) akzeptieren?
2. Stimmt meine SSL-Wrapper-Implementierung so?

Ich hoffe, ich hab nichts vergessen. Danke schonmal für die Mühe :)

Viele Grüße
Tom
 
Danke für die Antwort. Ich hab das Tutorial genau befolgt und ich bekomme trotzdem keine Antwort von dem Server.
 
Danke für die Problembeschreibung. Ich habe sie genau gelesen und es steht wirklich nichts nützliches drin.
 
Danke für die Problembeschreibung. Ich habe sie genau gelesen und es steht wirklich nichts nützliches drin.
Das war noch keine Problembeschreibung (wie du ja schon bemerkt hast). Ich versuche noch immer, es "funktionierend" zu implementieren. Ich hätte den Post editiert, sobald ich selbst mehr über das Problem weiß. Hab allerdings vergessen, mich für deinen Link zu bedanken: Danke :)
 
eigentlich war gemeint, das man dir schlecht helfen kann, wenn du nur sagst: "geht nicht"

kein code ... keine details was passiert... etc
 
So, ich bin endlich soweit. Ich hab das Ding nochmal neu geschrieben, weil ich das Gefühl hatte, dass ich das Protokoll noch nicht ganz verstanden hatte.
Code:
package myxmppimpl;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import sun.misc.BASE64Encoder;

public class MyXMPPImpl {
    private static SSLSocketFactory sslSocketFactory;

    public static void main(final String[] args) throws Exception {
//        String host = "192.168.60.161";
//        String host = "192.168.60.164";
//        String host = "192.168.0.100";
//        String host = "192.168.60.200";
        String host = "192.168.60.145";
        int port = 5222;
        String username = "testuser1@localhost".toLowerCase().trim();
        String password = "test";

        System.setProperty("javax.net.ssl.trustStore ", "myxmppimpl.NaiveTrustManager");

        // ######################################################################################################################################################################################
        // Create connection
        Socket socket = new Socket(host, port);
        BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8"));

        // ######################################################################################################################################################################################
        write(writer, "<stream:stream to=\"jabber.org\" xmlns=\"jabber:client\" xmlns:stream=\"http://etherx.jabber.org/streams\" version=\"1.0\">");
        read(reader);

        // ######################################################################################################################################################################################
        write(writer, "<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\"/>");
        read(reader);

        // ######################################################################################################################################################################################
        String userPass = "\0" + username + "\0" + password;
        String userPassBase64 = new BASE64Encoder().encode(userPass.getBytes());
        write(writer, "<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" mechanism=\"PLAIN\">" + userPassBase64 + "</auth>");
        read(reader);

        // ######################################################################################################################################################################################
        SSLSocket sslSocket = (SSLSocket) MyXMPPImpl.getSocketFactory().createSocket(socket, host, port, false);
        reader = new BufferedReader(new InputStreamReader(sslSocket.getInputStream()));
        writer = new BufferedWriter(new OutputStreamWriter(sslSocket.getOutputStream()));
        write(writer, "<message from='testuser1@localhost' to='testuser2@localhost' xml:lang='en'><body>Test-Nachricht</body></message>");
        read(reader);

        // ######################################################################################################################################################################################

    }

    private static void write(final BufferedWriter writer, final String msg) throws Exception {
        writer.write(msg);
        writer.flush();
        System.out.println("==> " + msg);
    }

    private static void read(final BufferedReader reader) throws Exception {
        Thread.sleep(100);
        System.out.print("<== ");
        int rec;
        while (reader.ready()) {
            rec = reader.read();
            System.out.print((char) rec);
        }
        System.out.println();
    }

    private static final SSLSocketFactory getSocketFactory() {
        if (sslSocketFactory == null) {
            try {
                TrustManager[] tm = new TrustManager[] { new NaiveTrustManager() };
                SSLContext context = SSLContext.getInstance("SSL");
                context.init(new KeyManager[0], tm, new SecureRandom());

                sslSocketFactory = context.getSocketFactory();

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return sslSocketFactory;
    }
}

class NaiveTrustManager implements X509TrustManager {
    /**
     * Doesn't throw an exception, so this is how it approves a certificate.
     * 
     * @see javax.net.ssl.X509TrustManager#checkClientTrusted(java.security.cert.X509Certificate[],
     *      String)
     **/
    @Override
    public void checkClientTrusted(final X509Certificate[] cert, final String authType)
            throws CertificateException {
    }

    /**
     * Doesn't throw an exception, so this is how it approves a certificate.
     * 
     * @see javax.net.ssl.X509TrustManager#checkServerTrusted(java.security.cert.X509Certificate[],
     *      String)
     **/
    @Override
    public void checkServerTrusted(final X509Certificate[] cert, final String authType)
            throws CertificateException {
    }

    /**
     * @see javax.net.ssl.X509TrustManager#getAcceptedIssuers()
     **/
    @Override
    public X509Certificate[] getAcceptedIssuers() {
        return null; // I've seen someone return new X509Certificate[ 0 ];
    }
}
Code:
==> <stream:stream to="jabber.org" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams" version="1.0">

<== <?xml version='1.0' encoding='UTF-8'?><stream:stream xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:client" from="localhost" id="baf16fa2" xml:lang="en" version="1.0">

==> <starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>

<== <stream:features><starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"></starttls><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>DIGEST-MD5</mechanism><mechanism>PLAIN</mechanism><mechanism>ANONYMOUS</mechanism><mechanism>CRAM-MD5</mechanism></mechanisms><compression xmlns="http://jabber.org/features/compress"><method>zlib</method></compression><auth xmlns="http://jabber.org/features/iq-auth"/><register xmlns="http://jabber.org/features/iq-register"/></stream:features>

==> <auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="PLAIN">AHRlc3R1c2VyMUBsb2NhbGhvc3QAdGVzdA==</auth>

<== <proceed xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>

Exception in thread "main" javax.net.ssl.SSLException: Received fatal alert: internal_error
    at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:190)
    at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:136)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1806)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:986)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1170)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:637)
    at com.sun.net.ssl.internal.ssl.AppOutputStream.write(AppOutputStream.java:88)
    at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:202)
    at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:272)
    at sun.nio.cs.StreamEncoder.implFlush(StreamEncoder.java:276)
    at sun.nio.cs.StreamEncoder.flush(StreamEncoder.java:122)
    at java.io.OutputStreamWriter.flush(OutputStreamWriter.java:212)
    at java.io.BufferedWriter.flush(BufferedWriter.java:236)
    at myxmppimpl.MyXMPPImpl.write(MyXMPPImpl.java:69)
    at myxmppimpl.MyXMPPImpl.main(MyXMPPImpl.java:60)
Anscheinend ist also irgendwas an meinem Request falsch.
Code:
<message from='testuser1@localhost' to='testuser2@localhost' xml:lang='en'><body>Test-Nachricht</body></message>
falsch. Ich hab bereits rumgesucht, komme aber auf keinen Fehler. Soweit ich das sehe, entspricht das genau dem RFC.

Viele Grüße und wie immer danke für eure Mühen,
Tom
 
Code:
System.setProperty("javax.net.ssl.trustStore ", "myxmppimpl.NaiveTrustManager");

erm ... du hast schon gelesen und verstanden dass das so nicht funktionieren kann? Der Author schreibt dazu dass es sehr schön wäre, wenn das funktionieren würde ... was es leider nicht tut

das ist der grund warum es einen zweiten ansatz auf der seite gibt ...:rolleyes:
 
Code:
System.setProperty("javax.net.ssl.trustStore ", "myxmppimpl.NaiveTrustManager");
erm ... du hast schon gelesen und verstanden dass das so nicht funktionieren kann? Der Author schreibt dazu dass es sehr schön wäre, wenn das funktionieren würde ... was es leider nicht tut

das ist der grund warum es einen zweiten ansatz auf der seite gibt ...:rolleyes:
Mist, das hab ich überlesen. Danke für den Hinweis.

Ich hab soeben bemerkt, dass ich über den Port 5222 kommuniziere. Das heißt, ich brauche mich überhaupt nicht um Zertifikate zu kümmern.

Daher habe ich jetzt einfach mal die Authentifzierung komplett ohne SSL versucht.

Code:
package myxmppimpl;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;

import sun.misc.BASE64Encoder;

public class MyXMPPImpl {
    public static void main(final String[] args) throws Exception {
        String host = "192.168.60.145";
        int port = 5222;
        String username = "testuser1@localhost".toLowerCase().trim();
        String password = "test";

        // ######################################################################################################################################################################################
        // Create connection
        Socket socket = new Socket(host, port);
        BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8"));

        // ######################################################################################################################################################################################
        write(writer, "<stream:stream to=\"jabber.org\" xmlns=\"jabber:client\" xmlns:stream=\"http://etherx.jabber.org/streams\" version=\"1.0\">");
        read(reader);

        // ######################################################################################################################################################################################
        String userPass = "\0" + username + "\0" + password;
        String userPassBase64 = new BASE64Encoder().encode(userPass.getBytes());
        write(writer, "<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" mechanism=\"PLAIN\">" + userPassBase64 + "</auth>");
        read(reader);

        // ######################################################################################################################################################################################
        write(writer, "<message from='testuser1@localhost' to='testuser2@localhost' xml:lang='en'><body>Test-Nachricht</body></message>");
        read(reader);

        // ######################################################################################################################################################################################

    }

    private static void write(final BufferedWriter writer, final String msg) throws Exception {
        writer.write(msg);
        writer.flush();
        System.out.println("==> " + msg);
    }

    private static void read(final BufferedReader reader) throws Exception {
        Thread.sleep(100);
        System.out.print("<== ");
        int rec;
        while (reader.ready()) {
            rec = reader.read();
            System.out.print((char) rec);
        }
        System.out.println();
    }
}

Code:
==> <stream:stream to="jabber.org" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams" version="1.0">
<== <?xml version='1.0' encoding='UTF-8'?><stream:stream xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:client" from="localhost" id="f310f04" xml:lang="en" version="1.0">
==> <auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="PLAIN">AHRlc3R1c2VyMUBsb2NhbGhvc3QAdGVzdA==</auth>
<== <stream:features><starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"></starttls><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>DIGEST-MD5</mechanism><mechanism>PLAIN</mechanism><mechanism>ANONYMOUS</mechanism><mechanism>CRAM-MD5</mechanism></mechanisms><compression xmlns="http://jabber.org/features/compress"><method>zlib</method></compression><auth xmlns="http://jabber.org/features/iq-auth"/><register xmlns="http://jabber.org/features/iq-register"/></stream:features>
==> <message from='testuser1@localhost' to='testuser2@localhost' xml:lang='en'><body>Test-Nachricht</body></message>
<== <success xmlns="urn:ietf:params:xml:ns:xmpp-sasl"/>
Ich bin gleichzeitig als testuser2@localhost in Pidgin auf dem Server eingeloggt. Allerdings kommt trotz der success-Meldung keine Nachricht bei testuser2 an.

Kurz ein Wort zu meiner Architektur:
localhost: 192.168.60.204
openFire: 192.168.60.245 (läuft auf einer turnkeylinux-VM)

Wie kann ich denn nachvollziehen, wieso diese Nachricht nicht ankommt? Oder habt ihr vielleicht sogar eine Idee, woran es liegen kann?
 
Zurück
Oben