]> WPIA git - gigi.git/blob - src/org/cacert/gigi/ping/SSLPinger.java
d6ebe71c2a3b3f3dd60f8463f82a6f51097202fe
[gigi.git] / src / org / cacert / gigi / ping / SSLPinger.java
1 package org.cacert.gigi.ping;
2
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;
12
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;
22
23 public class SSLPinger extends DomainPinger {
24
25     @Override
26     public void ping(String domain, String configuration, String expToken) {
27         try {
28             SocketChannel sch = SocketChannel.open();
29             String[] parts = configuration.split(":", 2);
30             sch.connect(new InetSocketAddress(domain, Integer.parseInt(parts[0])));
31             if (parts.length == 2) {
32                 switch (parts[1]) {
33                 case "xmpp":
34                     startXMPP(sch, false, domain);
35                     break;
36                 case "server-xmpp":
37                     startXMPP(sch, true, domain);
38                     break;
39                 case "smtp":
40                     startSMTP(sch);
41                     break;
42                 case "imap":
43                     startIMAP(sch);
44                     break;
45
46                 }
47             }
48             test(sch, domain);
49         } catch (IOException e) {
50             e.printStackTrace();
51         }
52
53     }
54
55     private void startIMAP(SocketChannel sch) throws IOException {
56         Socket s = sch.socket();
57         InputStream is = s.getInputStream();
58         OutputStream os = s.getOutputStream();
59         scanFor(is, "\n");
60         os.write("ENABLE STARTTLS\r\n".getBytes());
61         os.flush();
62         scanFor(is, "\n");
63     }
64
65     private void startXMPP(SocketChannel sch, boolean server, String domain) throws IOException {
66         Socket s = sch.socket();
67         InputStream is = s.getInputStream();
68         OutputStream os = s.getOutputStream();
69         os.write(("<stream:stream to=\"" + domain + "\" xmlns=\"jabber:" + (server ? "server" : "client") + "\"" + " xmlns:stream=\"http://etherx.jabber.org/streams\" version=\"1.0\">").getBytes());
70         os.flush();
71         os.write("<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\"/>".getBytes());
72         os.flush();
73         scanFor(is, "<proceed");
74         scanFor(is, ">");
75
76     }
77
78     private void scanFor(InputStream is, String scanFor) throws IOException {
79         int pos = 0;
80         while (pos < scanFor.length()) {
81             if (is.read() == scanFor.charAt(pos)) {
82                 pos++;
83             } else {
84                 pos = 0;
85             }
86         }
87     }
88
89     private void startSMTP(SocketChannel sch) throws IOException {
90         Socket s = sch.socket();
91         InputStream is = s.getInputStream();
92         readSMTP(is);
93         s.getOutputStream().write("EHLO ssl.pinger\r\n".getBytes());
94         s.getOutputStream().flush();
95         readSMTP(is);
96         s.getOutputStream().write("HELP\r\n".getBytes());
97         s.getOutputStream().flush();
98         readSMTP(is);
99         s.getOutputStream().write("STARTTLS\r\n".getBytes());
100         s.getOutputStream().flush();
101         readSMTP(is);
102     }
103
104     private void readSMTP(InputStream is) throws IOException {
105         int counter = 0;
106         boolean finish = true;
107         while (true) {
108             char c = (char) is.read();
109             if (counter == 3) {
110                 if (c == ' ') {
111                     finish = true;
112                 } else if (c == '-') {
113                     finish = false;
114                 } else {
115                     throw new Error("Invalid smtp: " + c);
116                 }
117             }
118             if (c == '\n') {
119                 if (finish) {
120                     return;
121                 }
122                 counter = 0;
123             } else {
124                 counter++;
125             }
126         }
127     }
128
129     private void test(SocketChannel sch, String domain) {
130         try {
131             SSLContext sc = SSLContext.getDefault();
132             SSLEngine se = sc.createSSLEngine();
133             ByteBuffer enc_in = ByteBuffer.allocate(se.getSession().getPacketBufferSize());
134             ByteBuffer enc_out = ByteBuffer.allocate(se.getSession().getPacketBufferSize());
135             ByteBuffer dec_in = ByteBuffer.allocate(se.getSession().getApplicationBufferSize());
136             ByteBuffer dec_out = ByteBuffer.allocate(se.getSession().getApplicationBufferSize());
137             se.setUseClientMode(true);
138             SSLParameters sp = se.getSSLParameters();
139             sp.setServerNames(Arrays.<SNIServerName>asList(new SNIHostName(domain)));
140             se.setSSLParameters(sp);
141             se.beginHandshake();
142             enc_in.limit(0);
143             while (se.getHandshakeStatus() != HandshakeStatus.FINISHED && se.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING) {
144                 switch (se.getHandshakeStatus()) {
145                 case NEED_WRAP:
146                     dec_out.limit(0);
147                     se.wrap(dec_out, enc_out);
148                     enc_out.flip();
149                     while (enc_out.remaining() > 0) {
150                         sch.write(enc_out);
151                     }
152                     enc_out.clear();
153                     break;
154                 case NEED_UNWRAP:
155                     if (enc_in.remaining() == 0) {
156                         enc_in.clear();
157                         sch.read(enc_in);
158                         enc_in.flip();
159                     }
160                     while (se.unwrap(enc_in, dec_in).getStatus() == Status.BUFFER_UNDERFLOW) {
161                         enc_in.position(enc_in.limit());
162                         enc_in.limit(enc_in.capacity());
163                         sch.read(enc_in);
164                         enc_in.flip();
165                     }
166                     enc_in.compact();
167                     enc_in.flip();
168                     break;
169                 case NEED_TASK:
170                     se.getDelegatedTask().run();
171                     break;
172                 case NOT_HANDSHAKING:
173                 case FINISHED:
174
175                 }
176
177             }
178             System.out.println("completed");
179             System.out.println(se.getSession().getCipherSuite());
180             X509Certificate[] peerCertificateChain = se.getSession().getPeerCertificateChain();
181             for (X509Certificate x509Certificate : peerCertificateChain) {
182                 System.out.println(x509Certificate.getSubjectDN().getName());
183             }
184         } catch (NoSuchAlgorithmException e) {
185             e.printStackTrace();
186         } catch (SSLException e) {
187             e.printStackTrace();
188         } catch (IOException e) {
189             e.printStackTrace();
190         }
191     }
192 }