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