X-Git-Url: https://code.wpia.club/?p=gigi.git;a=blobdiff_plain;f=src%2Forg%2Fcacert%2Fgigi%2Fping%2FSSLPinger.java;h=0b253c5f260bdda007da19b09ff16d560e68cc71;hp=78adc12ac9e6a76bc4d08ec34675c77445ff25b9;hb=99ef9ee7f8d4a2332e4f08c7a0b23cc84966f555;hpb=2824d1c165c501e2f3a8809044788b33b81f478a diff --git a/src/org/cacert/gigi/ping/SSLPinger.java b/src/org/cacert/gigi/ping/SSLPinger.java index 78adc12a..0b253c5f 100644 --- a/src/org/cacert/gigi/ping/SSLPinger.java +++ b/src/org/cacert/gigi/ping/SSLPinger.java @@ -3,192 +3,224 @@ package org.cacert.gigi.ping; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.math.BigInteger; import java.net.InetSocketAddress; import java.net.Socket; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; import java.util.Arrays; import javax.net.ssl.SNIHostName; import javax.net.ssl.SNIServerName; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; +import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.SSLEngineResult.Status; import javax.net.ssl.SSLException; import javax.net.ssl.SSLEngineResult.HandshakeStatus; import javax.net.ssl.SSLParameters; import javax.security.cert.X509Certificate; +import org.cacert.gigi.Certificate; +import org.cacert.gigi.Domain; +import org.cacert.gigi.User; + public class SSLPinger extends DomainPinger { - @Override - public void ping(String domain, String configuration, String expToken) { - try { - SocketChannel sch = SocketChannel.open(); - String[] parts = configuration.split(":", 2); - sch.connect(new InetSocketAddress(domain, Integer.parseInt(parts[0]))); - if (parts.length == 2) { - switch (parts[1]) { - case "xmpp": - startXMPP(sch, false, domain); - break; - case "server-xmpp": - startXMPP(sch, true, domain); - break; - case "smtp": - startSMTP(sch); - break; - case "imap": - startIMAP(sch); - break; - - } - } - test(sch, domain); - } catch (IOException e) { - e.printStackTrace(); - } - - } - - private void startIMAP(SocketChannel sch) throws IOException { - Socket s = sch.socket(); - InputStream is = s.getInputStream(); - OutputStream os = s.getOutputStream(); - scanFor(is, "\n"); - os.write("ENABLE STARTTLS\r\n".getBytes()); - os.flush(); - scanFor(is, "\n"); - } - - private void startXMPP(SocketChannel sch, boolean server, String domain) throws IOException { - Socket s = sch.socket(); - InputStream is = s.getInputStream(); - OutputStream os = s.getOutputStream(); - os.write(("") - .getBytes()); - os.flush(); - os.write("".getBytes()); - os.flush(); - scanFor(is, ""); - - } - - private void scanFor(InputStream is, String scanFor) throws IOException { - int pos = 0; - while (pos < scanFor.length()) { - if (is.read() == scanFor.charAt(pos)) { - pos++; - } else { - pos = 0; - } - } - } - - private void startSMTP(SocketChannel sch) throws IOException { - Socket s = sch.socket(); - InputStream is = s.getInputStream(); - readSMTP(is); - s.getOutputStream().write("EHLO ssl.pinger\r\n".getBytes()); - s.getOutputStream().flush(); - readSMTP(is); - s.getOutputStream().write("HELP\r\n".getBytes()); - s.getOutputStream().flush(); - readSMTP(is); - s.getOutputStream().write("STARTTLS\r\n".getBytes()); - s.getOutputStream().flush(); - readSMTP(is); - } - - private void readSMTP(InputStream is) throws IOException { - int counter = 0; - boolean finish = true; - while (true) { - char c = (char) is.read(); - if (counter == 3) { - if (c == ' ') { - finish = true; - } else if (c == '-') { - finish = false; - } else { - throw new Error("Invalid smtp: " + c); - } - } - if (c == '\n') { - if (finish) { - return; - } - counter = 0; - } else { - counter++; - } - } - } - - private void test(SocketChannel sch, String domain) { - try { - SSLContext sc = SSLContext.getDefault(); - SSLEngine se = sc.createSSLEngine(); - ByteBuffer enc_in = ByteBuffer.allocate(se.getSession().getPacketBufferSize()); - ByteBuffer enc_out = ByteBuffer.allocate(se.getSession().getPacketBufferSize()); - ByteBuffer dec_in = ByteBuffer.allocate(se.getSession().getApplicationBufferSize()); - ByteBuffer dec_out = ByteBuffer.allocate(se.getSession().getApplicationBufferSize()); - se.setUseClientMode(true); - SSLParameters sp = se.getSSLParameters(); - sp.setServerNames(Arrays. asList(new SNIHostName(domain))); - se.setSSLParameters(sp); - se.beginHandshake(); - enc_in.limit(0); - while (se.getHandshakeStatus() != HandshakeStatus.FINISHED - && se.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING) { - switch (se.getHandshakeStatus()) { - case NEED_WRAP: - dec_out.limit(0); - se.wrap(dec_out, enc_out); - enc_out.flip(); - while (enc_out.remaining() > 0) { - sch.write(enc_out); - } - enc_out.clear(); - break; - case NEED_UNWRAP: - if (enc_in.remaining() == 0) { - enc_in.clear(); - sch.read(enc_in); - enc_in.flip(); - } - while (se.unwrap(enc_in, dec_in).getStatus() == Status.BUFFER_UNDERFLOW) { - enc_in.position(enc_in.limit()); - enc_in.limit(enc_in.capacity()); - sch.read(enc_in); - enc_in.flip(); - } - enc_in.compact(); - enc_in.flip(); - break; - case NEED_TASK: - se.getDelegatedTask().run(); - break; - case NOT_HANDSHAKING: - case FINISHED: - - } - - } - System.out.println("completed"); - System.out.println(se.getSession().getCipherSuite()); - X509Certificate[] peerCertificateChain = se.getSession().getPeerCertificateChain(); - for (X509Certificate x509Certificate : peerCertificateChain) { - System.out.println(x509Certificate.getSubjectDN().getName()); - } - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - } catch (SSLException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } - } + public static final String[] TYPES = new String[] { + "xmpp", "server-xmpp", "smtp", "imap" + }; + + private KeyStore truststore; + + public SSLPinger(KeyStore truststore) { + this.truststore = truststore; + } + + @Override + public String ping(Domain domain, String configuration, User u) { + try (SocketChannel sch = SocketChannel.open()) { + String[] parts = configuration.split(":", 2); + sch.connect(new InetSocketAddress(domain.getSuffix(), Integer.parseInt(parts[0]))); + if (parts.length == 2) { + switch (parts[1]) { + case "xmpp": + startXMPP(sch, false, domain.getSuffix()); + break; + case "server-xmpp": + startXMPP(sch, true, domain.getSuffix()); + break; + case "smtp": + startSMTP(sch); + break; + case "imap": + startIMAP(sch); + break; + + } + } + return test(sch, domain.getSuffix(), u); + } catch (IOException e) { + return "Connecton failed"; + } + + } + + private void startIMAP(SocketChannel sch) throws IOException { + Socket s = sch.socket(); + InputStream is = s.getInputStream(); + OutputStream os = s.getOutputStream(); + scanFor(is, "\n"); + os.write("ENABLE STARTTLS\r\n".getBytes()); + os.flush(); + scanFor(is, "\n"); + } + + private void startXMPP(SocketChannel sch, boolean server, String domain) throws IOException { + Socket s = sch.socket(); + InputStream is = s.getInputStream(); + OutputStream os = s.getOutputStream(); + os.write(("").getBytes()); + os.flush(); + os.write("".getBytes()); + os.flush(); + scanFor(is, ""); + + } + + private void scanFor(InputStream is, String scanFor) throws IOException { + int pos = 0; + while (pos < scanFor.length()) { + if (is.read() == scanFor.charAt(pos)) { + pos++; + } else { + pos = 0; + } + } + } + + private void startSMTP(SocketChannel sch) throws IOException { + Socket s = sch.socket(); + InputStream is = s.getInputStream(); + readSMTP(is); + s.getOutputStream().write("EHLO ssl.pinger\r\n".getBytes()); + s.getOutputStream().flush(); + readSMTP(is); + s.getOutputStream().write("HELP\r\n".getBytes()); + s.getOutputStream().flush(); + readSMTP(is); + s.getOutputStream().write("STARTTLS\r\n".getBytes()); + s.getOutputStream().flush(); + readSMTP(is); + } + + private void readSMTP(InputStream is) throws IOException { + int counter = 0; + boolean finish = true; + while (true) { + char c = (char) is.read(); + if (counter == 3) { + if (c == ' ') { + finish = true; + } else if (c == '-') { + finish = false; + } else { + throw new Error("Invalid smtp: " + c); + } + } + if (c == '\n') { + if (finish) { + return; + } + counter = 0; + } else { + counter++; + } + } + } + + private String test(SocketChannel sch, String domain, User subject) { + try { + SSLContext sc = SSLContext.getInstance("SSL"); + try { + TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509"); + tmf.init(truststore); + sc.init(null, tmf.getTrustManagers(), new SecureRandom()); + } catch (KeyManagementException e) { + e.printStackTrace(); + } catch (KeyStoreException e) { + e.printStackTrace(); + } + SSLEngine se = sc.createSSLEngine(); + ByteBuffer enc_in = ByteBuffer.allocate(se.getSession().getPacketBufferSize()); + ByteBuffer enc_out = ByteBuffer.allocate(se.getSession().getPacketBufferSize()); + ByteBuffer dec_in = ByteBuffer.allocate(se.getSession().getApplicationBufferSize()); + ByteBuffer dec_out = ByteBuffer.allocate(se.getSession().getApplicationBufferSize()); + se.setUseClientMode(true); + SSLParameters sp = se.getSSLParameters(); + sp.setServerNames(Arrays.asList(new SNIHostName(domain))); + se.setSSLParameters(sp); + se.beginHandshake(); + enc_in.limit(0); + while (se.getHandshakeStatus() != HandshakeStatus.FINISHED && se.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING) { + switch (se.getHandshakeStatus()) { + case NEED_WRAP: + dec_out.limit(0); + se.wrap(dec_out, enc_out); + enc_out.flip(); + while (enc_out.remaining() > 0) { + sch.write(enc_out); + } + enc_out.clear(); + break; + case NEED_UNWRAP: + if (enc_in.remaining() == 0) { + enc_in.clear(); + sch.read(enc_in); + enc_in.flip(); + } + while (se.unwrap(enc_in, dec_in).getStatus() == Status.BUFFER_UNDERFLOW) { + enc_in.position(enc_in.limit()); + enc_in.limit(enc_in.capacity()); + sch.read(enc_in); + enc_in.flip(); + } + enc_in.compact(); + enc_in.flip(); + break; + case NEED_TASK: + se.getDelegatedTask().run(); + break; + case NOT_HANDSHAKING: + case FINISHED: + + } + + } + X509Certificate[] peerCertificateChain = se.getSession().getPeerCertificateChain(); + X509Certificate first = peerCertificateChain[0]; + + BigInteger serial = first.getSerialNumber(); + Certificate c = Certificate.getBySerial(serial.toString(16)); + if (c.getOwnerId() != subject.getId()) { + return "Owner mismatch"; + } + return PING_SUCCEDED; + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + return "Security failed"; + } catch (SSLException e) { + e.printStackTrace(); + return "Security failed"; + } catch (IOException e) { + e.printStackTrace(); + return "Connection closed"; + } + } }