1 package org.cacert.gigi.ping;
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.io.OutputStream;
6 import java.net.InetSocketAddress;
7 import java.net.Socket;
8 import java.nio.ByteBuffer;
9 import java.nio.channels.SocketChannel;
10 import java.security.NoSuchAlgorithmException;
11 import java.util.Arrays;
13 import javax.net.ssl.SNIHostName;
14 import javax.net.ssl.SNIServerName;
15 import javax.net.ssl.SSLContext;
16 import javax.net.ssl.SSLEngine;
17 import javax.net.ssl.SSLEngineResult.Status;
18 import javax.net.ssl.SSLException;
19 import javax.net.ssl.SSLEngineResult.HandshakeStatus;
20 import javax.net.ssl.SSLParameters;
21 import javax.security.cert.X509Certificate;
23 import org.cacert.gigi.Domain;
24 import org.cacert.gigi.User;
26 public class SSLPinger extends DomainPinger {
28 public static final String[] TYPES = new String[] {
29 "xmpp", "server-xmpp", "smtp", "imap"
33 public String ping(Domain domain, String configuration, User u) {
35 SocketChannel sch = SocketChannel.open();
36 String[] parts = configuration.split(":", 2);
37 sch.connect(new InetSocketAddress(domain.getSuffix(), Integer.parseInt(parts[0])));
38 if (parts.length == 2) {
41 startXMPP(sch, false, domain.getSuffix());
44 startXMPP(sch, true, domain.getSuffix());
55 return test(sch, domain.getSuffix());
56 } catch (IOException e) {
57 return "Connecton failed";
62 private void startIMAP(SocketChannel sch) throws IOException {
63 Socket s = sch.socket();
64 InputStream is = s.getInputStream();
65 OutputStream os = s.getOutputStream();
67 os.write("ENABLE STARTTLS\r\n".getBytes());
72 private void startXMPP(SocketChannel sch, boolean server, String domain) throws IOException {
73 Socket s = sch.socket();
74 InputStream is = s.getInputStream();
75 OutputStream os = s.getOutputStream();
76 os.write(("<stream:stream to=\"" + domain + "\" xmlns=\"jabber:" + (server ? "server" : "client") + "\"" + " xmlns:stream=\"http://etherx.jabber.org/streams\" version=\"1.0\">").getBytes());
78 os.write("<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\"/>".getBytes());
80 scanFor(is, "<proceed");
85 private void scanFor(InputStream is, String scanFor) throws IOException {
87 while (pos < scanFor.length()) {
88 if (is.read() == scanFor.charAt(pos)) {
96 private void startSMTP(SocketChannel sch) throws IOException {
97 Socket s = sch.socket();
98 InputStream is = s.getInputStream();
100 s.getOutputStream().write("EHLO ssl.pinger\r\n".getBytes());
101 s.getOutputStream().flush();
103 s.getOutputStream().write("HELP\r\n".getBytes());
104 s.getOutputStream().flush();
106 s.getOutputStream().write("STARTTLS\r\n".getBytes());
107 s.getOutputStream().flush();
111 private void readSMTP(InputStream is) throws IOException {
113 boolean finish = true;
115 char c = (char) is.read();
119 } else if (c == '-') {
122 throw new Error("Invalid smtp: " + c);
136 private String test(SocketChannel sch, String domain) {
138 SSLContext sc = SSLContext.getDefault();
139 SSLEngine se = sc.createSSLEngine();
140 ByteBuffer enc_in = ByteBuffer.allocate(se.getSession().getPacketBufferSize());
141 ByteBuffer enc_out = ByteBuffer.allocate(se.getSession().getPacketBufferSize());
142 ByteBuffer dec_in = ByteBuffer.allocate(se.getSession().getApplicationBufferSize());
143 ByteBuffer dec_out = ByteBuffer.allocate(se.getSession().getApplicationBufferSize());
144 se.setUseClientMode(true);
145 SSLParameters sp = se.getSSLParameters();
146 sp.setServerNames(Arrays.<SNIServerName>asList(new SNIHostName(domain)));
147 se.setSSLParameters(sp);
150 while (se.getHandshakeStatus() != HandshakeStatus.FINISHED && se.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING) {
151 switch (se.getHandshakeStatus()) {
154 se.wrap(dec_out, enc_out);
156 while (enc_out.remaining() > 0) {
162 if (enc_in.remaining() == 0) {
167 while (se.unwrap(enc_in, dec_in).getStatus() == Status.BUFFER_UNDERFLOW) {
168 enc_in.position(enc_in.limit());
169 enc_in.limit(enc_in.capacity());
177 se.getDelegatedTask().run();
179 case NOT_HANDSHAKING:
185 System.out.println("completed");
186 System.out.println(se.getSession().getCipherSuite());
187 X509Certificate[] peerCertificateChain = se.getSession().getPeerCertificateChain();
188 for (X509Certificate x509Certificate : peerCertificateChain) {
189 System.out.println(x509Certificate.getSubjectDN().getName());
191 return PING_SUCCEDED;
192 } catch (NoSuchAlgorithmException e) {
194 return "Security failed";
195 } catch (SSLException e) {
197 return "Security failed";
198 } catch (IOException e) {
200 return "Connection closed";