]> WPIA git - gigi.git/blob - tests/org/cacert/gigi/ping/TestSSL.java
upd: split certificate issuance as organisation into seperate
[gigi.git] / tests / org / cacert / gigi / ping / TestSSL.java
1 package org.cacert.gigi.ping;
2
3 import static org.junit.Assert.*;
4 import static org.junit.Assume.*;
5
6 import java.io.IOException;
7 import java.net.Socket;
8 import java.net.URL;
9 import java.net.URLEncoder;
10 import java.security.GeneralSecurityException;
11 import java.security.KeyManagementException;
12 import java.security.KeyPair;
13 import java.security.NoSuchAlgorithmException;
14 import java.security.Principal;
15 import java.security.PrivateKey;
16 import java.security.SecureRandom;
17 import java.security.cert.CertificateException;
18 import java.security.cert.X509Certificate;
19 import java.sql.SQLException;
20 import java.util.regex.Matcher;
21 import java.util.regex.Pattern;
22
23 import javax.net.ssl.KeyManager;
24 import javax.net.ssl.SSLContext;
25 import javax.net.ssl.SSLServerSocket;
26 import javax.net.ssl.SSLServerSocketFactory;
27 import javax.net.ssl.TrustManager;
28 import javax.net.ssl.X509KeyManager;
29 import javax.net.ssl.X509TrustManager;
30
31 import org.cacert.gigi.GigiApiException;
32 import org.cacert.gigi.dbObjects.Certificate;
33 import org.cacert.gigi.dbObjects.Certificate.CSRType;
34 import org.cacert.gigi.dbObjects.CertificateProfile;
35 import org.cacert.gigi.dbObjects.User;
36 import org.cacert.gigi.pages.account.domain.DomainOverview;
37 import org.cacert.gigi.testUtils.IOUtils;
38 import org.cacert.gigi.testUtils.PingTest;
39 import org.cacert.gigi.testUtils.TestEmailReceiver.TestMail;
40 import org.junit.Test;
41
42 public class TestSSL extends PingTest {
43
44     public abstract static class AsyncTask<T> {
45
46         T res;
47
48         Thread runner;
49
50         Exception ex;
51
52         public T join() throws InterruptedException {
53             runner.join();
54             if (ex != null) {
55                 throw new Error(ex);
56             }
57             return res;
58         }
59
60         public void start() {
61             runner = new Thread() {
62
63                 @Override
64                 public void run() {
65                     try {
66                         res = AsyncTask.this.run();
67                     } catch (Exception e) {
68                         ex = e;
69                     }
70                 }
71             };
72             runner.start();
73         }
74
75         public abstract T run() throws Exception;
76
77     }
78
79     private KeyPair kp;
80
81     private Certificate c;
82
83     @Test(timeout = 70000)
84     public void sslAndMailSuccess() throws IOException, InterruptedException, SQLException, GeneralSecurityException, GigiApiException {
85         testEmailAndSSL(0, 0, true);
86     }
87
88     @Test(timeout = 70000)
89     public void sslWongTypeAndMailSuccess() throws IOException, InterruptedException, SQLException, GeneralSecurityException, GigiApiException {
90         testEmailAndSSL(1, 0, true);
91     }
92
93     @Test(timeout = 70000)
94     public void sslOneMissingAndMailSuccess() throws IOException, InterruptedException, SQLException, GeneralSecurityException, GigiApiException {
95         testEmailAndSSL(2, 0, true);
96     }
97
98     @Test(timeout = 70000)
99     public void sslBothMissingAndMailSuccess() throws IOException, InterruptedException, SQLException, GeneralSecurityException, GigiApiException {
100         testEmailAndSSL(3, 0, true);
101     }
102
103     @Test(timeout = 70000)
104     public void sslWrongTypeAndMailFail() throws IOException, InterruptedException, SQLException, GeneralSecurityException, GigiApiException {
105         testEmailAndSSL(1, 1, false);
106     }
107
108     /**
109      * @param sslVariant
110      *            <ul>
111      *            <li>0= all valid</li>
112      *            <li>1= wrong type</li>
113      *            <li>2= one server missing</li>
114      *            <li>3= both servers missing</li>
115      *            </ul>
116      * @param emailVariant
117      * @param successSSL
118      * @param successMail
119      * @throws IOException
120      * @throws InterruptedException
121      * @throws SQLException
122      * @throws GeneralSecurityException
123      * @throws GigiApiException
124      */
125
126     private void testEmailAndSSL(int sslVariant, int emailVariant, boolean successMail) throws IOException, InterruptedException, SQLException, GeneralSecurityException, GigiApiException {
127         String test = getTestProps().getProperty("domain.local");
128         assumeNotNull(test);
129         URL u = new URL("https://" + getServerName() + DomainOverview.PATH);
130
131         initailizeDomainForm(u);
132
133         createCertificate(test, CertificateProfile.getByName(sslVariant == 1 ? "client" : "server"));
134         final SSLServerSocket sss = createSSLServer(kp.getPrivate(), c.cert());
135         int port = sss.getLocalPort();
136         final SSLServerSocket sss2 = createSSLServer(kp.getPrivate(), c.cert());
137         int port2 = sss2.getLocalPort();
138         if (sslVariant == 3 || sslVariant == 2) {
139             sss2.close();
140             if (sslVariant == 3) {
141                 sss.close();
142             }
143         }
144         String content = "adddomain&newdomain=" + URLEncoder.encode(test, "UTF-8") + //
145                 "&emailType=y&email=2&SSLType=y" + //
146                 "&ssl-type-0=direct&ssl-port-0=" + port + //
147                 "&ssl-type-1=direct&ssl-port-1=" + port2 + //
148                 "&ssl-type-2=direct&ssl-port-2=" + //
149                 "&ssl-type-3=direct&ssl-port-3=" + //
150                 "&adddomain&csrf=" + csrf;
151         URL u2 = sendDomainForm(u, content);
152         boolean firstSucceeds = sslVariant != 0 && sslVariant != 2;
153         AsyncTask<Boolean> ass = new AsyncTask<Boolean>() {
154
155             @Override
156             public Boolean run() throws Exception {
157                 return acceptSSLServer(sss);
158             }
159         };
160         ass.start();
161         System.out.println(port + " and " + port2 + " ready");
162         System.err.println(port + " and " + port2 + " ready");
163         boolean accept2 = acceptSSLServer(sss2);
164         boolean accept1 = ass.join();
165         assertTrue(firstSucceeds ^ accept1);
166         boolean secondsSucceeds = sslVariant != 0;
167         assertTrue(secondsSucceeds ^ accept2);
168
169         TestMail mail = getMailReciever().receive();
170         if (emailVariant == 0) {
171             mail.verify();
172         }
173         waitForPings(3);
174
175         String newcontent = IOUtils.readURL(cookie(u2.openConnection(), cookie));
176         Pattern pat = Pattern.compile("<td>ssl</td>\\s*<td>success</td>");
177         Matcher matcher = pat.matcher(newcontent);
178         assertTrue(newcontent, firstSucceeds ^ matcher.find());
179         assertTrue(newcontent, secondsSucceeds ^ matcher.find());
180         assertFalse(newcontent, matcher.find());
181         pat = Pattern.compile("<td>email</td>\\s*<td>success</td>");
182         assertTrue(newcontent, !successMail ^ pat.matcher(newcontent).find());
183     }
184
185     private void createCertificate(String test, CertificateProfile profile) throws GeneralSecurityException, IOException, SQLException, InterruptedException, GigiApiException {
186         kp = generateKeypair();
187         String csr = generatePEMCSR(kp, "CN=" + test);
188         User u = User.getById(id);
189         c = new Certificate(u, u, Certificate.buildDN("CN", test), "sha256", csr, CSRType.CSR, profile);
190         c.issue(null, "2y", u).waitFor(60000);
191     }
192
193     private boolean acceptSSLServer(SSLServerSocket sss) throws IOException {
194         try (Socket s = sss.accept()) {
195             s.getOutputStream().write('b');
196             s.getOutputStream().close();
197             return true;
198         } catch (IOException e) {
199             return false;
200         }
201     }
202
203     private SSLServerSocket createSSLServer(final PrivateKey priv, final X509Certificate cert) throws Error, IOException {
204         SSLContext sc;
205         try {
206             sc = SSLContext.getInstance("SSL");
207             sc.init(new KeyManager[] {
208                 new X509KeyManager() {
209
210                     @Override
211                     public String[] getServerAliases(String keyType, Principal[] issuers) {
212                         return new String[] {
213                             "server"
214                         };
215                     }
216
217                     @Override
218                     public PrivateKey getPrivateKey(String alias) {
219                         return priv;
220                     }
221
222                     @Override
223                     public String[] getClientAliases(String keyType, Principal[] issuers) {
224                         throw new Error();
225                     }
226
227                     @Override
228                     public X509Certificate[] getCertificateChain(String alias) {
229                         return new X509Certificate[] {
230                             cert
231                         };
232                     }
233
234                     @Override
235                     public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
236                         throw new Error();
237                     }
238
239                     @Override
240                     public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
241                         return "server";
242                     }
243
244                 }
245             }, new TrustManager[] {
246                 new X509TrustManager() {
247
248                     @Override
249                     public X509Certificate[] getAcceptedIssuers() {
250                         return null;
251                     }
252
253                     @Override
254                     public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
255
256                     @Override
257                     public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
258                 }
259             }, new SecureRandom());
260         } catch (NoSuchAlgorithmException e) {
261             e.printStackTrace();
262             throw new Error(e);
263         } catch (KeyManagementException e) {
264             e.printStackTrace();
265             throw new Error(e);
266         }
267
268         SSLServerSocketFactory sssf = sc.getServerSocketFactory();
269         return (SSLServerSocket) sssf.createServerSocket(0);
270     }
271
272     public static void main(String[] args) throws Exception {
273         initEnvironment();
274         TestSSL t1 = new TestSSL();
275         t1.sslAndMailSuccess();
276         tearDownServer();
277     }
278
279 }