1 package club.wpia.gigi.pages.main;
3 import static org.hamcrest.MatcherAssert.assertThat;
4 import static org.junit.Assert.*;
6 import java.io.IOException;
7 import java.io.OutputStream;
8 import java.net.HttpURLConnection;
10 import java.net.URLConnection;
11 import java.net.URLEncoder;
12 import java.security.GeneralSecurityException;
13 import java.security.KeyPair;
14 import java.security.PrivateKey;
15 import java.util.Base64;
16 import java.util.regex.Matcher;
17 import java.util.regex.Pattern;
19 import org.hamcrest.CoreMatchers;
20 import org.junit.Test;
21 import org.junit.runner.RunWith;
22 import org.junit.runners.Parameterized;
23 import org.junit.runners.Parameterized.Parameters;
25 import club.wpia.gigi.GigiApiException;
26 import club.wpia.gigi.dbObjects.Certificate;
27 import club.wpia.gigi.dbObjects.Certificate.CertificateStatus;
28 import club.wpia.gigi.dbObjects.Digest;
29 import club.wpia.gigi.dbObjects.Job;
30 import club.wpia.gigi.pages.account.certs.CertificateRequest;
31 import club.wpia.gigi.testUtils.ClientTest;
32 import club.wpia.gigi.testUtils.IOUtils;
33 import club.wpia.gigi.util.AuthorizationContext;
34 import club.wpia.gigi.util.PEM;
36 @RunWith(Parameterized.class)
37 public class KeyCompromiseTest extends ClientTest {
39 private static class TestParameters {
41 private final String query;
43 private final String error;
45 public TestParameters(String query, String error) {
50 public String getError() {
54 public String getQuery() {
59 public String toString() {
60 return query + ": " + error;
64 private Certificate cert;
66 private String serial;
68 private PrivateKey priv;
70 private TestParameters pm;
72 public KeyCompromiseTest(TestParameters pm) throws GeneralSecurityException, IOException, GigiApiException, InterruptedException {
74 KeyPair kp = generateKeypair();
75 priv = kp.getPrivate();
76 String csr = generatePEMCSR(kp, "CN=test");
77 CertificateRequest cr = new CertificateRequest(new AuthorizationContext(u, u), csr);
78 cr.update(CertificateRequest.DEFAULT_CN, Digest.SHA512.toString(), "client", null, null, "email:" + email + "\n");
80 Job j = cert.issue(null, "2y", u);
82 serial = cert.getSerial();
85 @Parameters(name = "{0}")
86 public static Object[][] getParams() {
87 return new Object[][] {
88 params("serial=%serial&priv=%priv", null),// serial+key
89 params("serial=0000%serial&priv=%priv", null),// leading Zeros
90 params("serial=0000%Serial&priv=%priv", null),// upper case
91 params("cert=%cert&priv=%priv", null),// cert+key
92 params("serial=%serial&signature=%signature", null),
94 params("serial=0000&priv=%priv", KeyCompromiseForm.NOT_FOUND.getRaw()),
95 params("serial=0lkd&priv=%priv", KeyCompromiseForm.NOT_FOUND.getRaw()),
97 params("cert=%tamperedCert&priv=%priv", "not be parsed"),
98 params("cert=%cert&priv=%tamperedPriv", "Private Key is malformed"),
99 params("serial=1&priv=%priv", KeyCompromiseForm.NOT_FOUND.getRaw()),
100 params("serial=1%serial&priv=%priv", KeyCompromiseForm.NOT_FOUND.getRaw()),
101 // missing certificate identification
102 params("serial=&cert=&priv=%priv", "identification"),
103 params("cert=&priv=%priv", "identification"),
104 params("serial=&priv=%priv", "identification"),
105 params("priv=%priv", "identification"),
107 params("serial=%serial&priv=&signature=", "No verification"),
108 params("serial=%serial&signature=", "No verification"),
109 params("serial=%serial&priv=", "No verification"),
110 params("serial=%serial", "No verification"),
111 params("cert=%cert&signature=%tamperedSignature", "Verification does not match"),
113 params("cert=-_&signature=%signature", "certificate could not be parsed"),
114 params("cert=%cert&signature=-_", "Signature is malformed"),
115 params("cert=%cert&priv=-_", "Private Key is malformed"),
119 private static Object[] params(String query, String error) {
120 return new Object[] {
121 new TestParameters(query, error)
125 private String getQuery(String data) {
128 Pattern challenge = Pattern.compile(" data-challenge=\"([a-zA-Z0-9]+)\"");
129 Matcher m = challenge.matcher(data);
135 byte[] privKeyData = priv.getEncoded();
136 String privKey = URLEncoder.encode(PEM.encode("PRIVATE KEY", privKeyData), "UTF-8");
138 String privKeyTampered = URLEncoder.encode(PEM.encode("PRIVATE KEY", privKeyData), "UTF-8");
139 byte[] tampered = cert.cert().getEncoded();
141 String query = pm.getQuery();
142 query = query.replace("%serial", serial.toLowerCase())//
143 .replace("%Serial", serial.toUpperCase())//
144 .replace("%priv", privKey)//
145 .replace("%cert", URLEncoder.encode(PEM.encode("CERTIFICATE", cert.cert().getEncoded()), "UTF-8"))//
146 .replace("%tamperedCert", URLEncoder.encode(PEM.encode("CERTIFICATE", tampered), "UTF-8"))//
147 .replace("%tamperedPriv", privKeyTampered);
149 byte[] sigRaw = KeyCompromiseForm.sign(priv, cData);
150 String sigData = URLEncoder.encode(Base64.getEncoder().encodeToString(sigRaw), "UTF-8");
152 query = query.replace("%signature", sigData);
153 query = query.replace("%tamperedSignature", URLEncoder.encode(Base64.getEncoder().encodeToString(sigRaw), "UTF-8"));
156 } catch (IOException e) {
158 } catch (GeneralSecurityException e) {
164 public void testExecution() throws IOException, InterruptedException, GigiApiException, GeneralSecurityException {
165 URLConnection uc = new URL("https://" + getServerName() + KeyCompromisePage.PATH).openConnection();
166 String cookie = stripCookie(uc.getHeaderField("Set-Cookie"));
167 String content = IOUtils.readURL(uc);
168 String csrf = getCSRF(0, content);
170 uc = new URL("https://" + getServerName() + KeyCompromisePage.PATH).openConnection();
172 uc.setDoOutput(true);
173 OutputStream os = uc.getOutputStream();
174 os.write(("csrf=" + URLEncoder.encode(csrf, "UTF-8") + "&" //
175 + getQuery(content)//
176 ).getBytes("UTF-8"));
178 HttpURLConnection huc = (HttpURLConnection) uc;
180 String result = IOUtils.readURL(huc);
181 String error = pm.getError();
183 assertThat(result, hasNoError());
184 assertRevoked(result);
185 } else if ("error".equals(error)) {
186 assertThat(result, hasError());
187 assertNotEquals(CertificateStatus.REVOKED, cert.getStatus());
189 assertThat(fetchStartErrorMessage(result), CoreMatchers.containsString(error));
190 assertNotEquals(CertificateStatus.REVOKED, cert.getStatus());
194 private void assertRevoked(String result) {
195 assertThat(result, CoreMatchers.containsString("Certificate is revoked"));
196 assertEquals(CertificateStatus.REVOKED, cert.getStatus());