]> WPIA git - gigi.git/blob - src/org/cacert/gigi/pages/account/IssueCertificateForm.java
Implement SPKAC Challanges.
[gigi.git] / src / org / cacert / gigi / pages / account / IssueCertificateForm.java
1 package org.cacert.gigi.pages.account;
2
3 import java.io.BufferedReader;
4 import java.io.IOException;
5 import java.io.InputStreamReader;
6 import java.io.OutputStream;
7 import java.io.PrintWriter;
8 import java.security.GeneralSecurityException;
9 import java.security.PublicKey;
10 import java.security.interfaces.DSAPublicKey;
11 import java.security.interfaces.ECPublicKey;
12 import java.security.interfaces.RSAPublicKey;
13 import java.sql.SQLException;
14 import java.util.Base64;
15 import java.util.HashMap;
16 import java.util.Map;
17
18 import javax.servlet.http.HttpServletRequest;
19
20 import org.cacert.gigi.Certificate;
21 import org.cacert.gigi.Digest;
22 import org.cacert.gigi.EmailAddress;
23 import org.cacert.gigi.GigiApiException;
24 import org.cacert.gigi.Language;
25 import org.cacert.gigi.User;
26 import org.cacert.gigi.Certificate.CSRType;
27 import org.cacert.gigi.output.Form;
28 import org.cacert.gigi.output.template.HashAlgorithms;
29 import org.cacert.gigi.output.template.IterableDataset;
30 import org.cacert.gigi.output.template.Template;
31 import org.cacert.gigi.pages.LoginPage;
32 import org.cacert.gigi.pages.Page;
33 import org.cacert.gigi.util.RandomToken;
34
35 import sun.security.pkcs10.PKCS10;
36
37 /**
38  * This class represents a form that is used for issuing certificates. This
39  * class uses "sun.security" and therefore needs "-XDignore.symbol.file"
40  */
41 public class IssueCertificateForm extends Form {
42
43     User u;
44
45     Digest selectedDigest = Digest.getDefault();
46
47     boolean login;
48
49     String csr;
50
51     private final static Template t = new Template(IssueCertificateForm.class.getResource("IssueCertificateForm.templ"));
52
53     private final static Template tIni = new Template(MailCertificateAdd.class.getResource("RequestCertificate.templ"));
54
55     String spkacChallange;
56
57     public IssueCertificateForm(HttpServletRequest hsr) {
58         super(hsr);
59         u = LoginPage.getUser(hsr);
60         spkacChallange = RandomToken.generateToken(16);
61     }
62
63     Certificate result;
64
65     private CSRType csrType;
66
67     public Certificate getResult() {
68         return result;
69     }
70
71     @Override
72     public boolean submit(PrintWriter out, HttpServletRequest req) {
73         String csr = req.getParameter("CSR");
74         String spkac = req.getParameter("SPKAC");
75         try {
76             if (csr != null) {
77                 PKCS10 parsed = parseCSR(csr);
78                 out.println(parsed.getSubjectName().getCommonName());
79                 out.println(parsed.getSubjectName().getCountry());
80                 out.println("CSR DN: " + parsed.getSubjectName() + "<br/>");
81                 PublicKey pk = parsed.getSubjectPublicKeyInfo();
82                 out.println("Type: " + pk.getAlgorithm() + "<br/>");
83                 if (pk instanceof RSAPublicKey) {
84                     out.println("Exponent: " + ((RSAPublicKey) pk).getPublicExponent() + "<br/>");
85                     out.println("Length: " + ((RSAPublicKey) pk).getModulus().bitLength());
86                 } else if (pk instanceof DSAPublicKey) {
87                     DSAPublicKey dpk = (DSAPublicKey) pk;
88                     out.println("Length: " + dpk.getY().bitLength() + "<br/>");
89                     out.println(dpk.getParams());
90                 } else if (pk instanceof ECPublicKey) {
91                     ECPublicKey epk = (ECPublicKey) pk;
92                     out.println("Length-x: " + epk.getW().getAffineX().bitLength() + "<br/>");
93                     out.println("Length-y: " + epk.getW().getAffineY().bitLength() + "<br/>");
94                     out.println(epk.getParams().getCurve());
95                 }
96                 out.println("<br/>digest: sha256<br/>");
97                 this.csr = csr;
98                 this.csrType = CSRType.CSR;
99             } else if (spkac != null) {
100                 String cleanedSPKAC = "SPKAC=" + spkac.replaceAll("[\r\n]", "");
101                 try {
102                     checkSPKAC(cleanedSPKAC, spkacChallange);
103                     this.csr = cleanedSPKAC;
104                     this.csrType = CSRType.SPKAC;
105                 } catch (GigiApiException e) {
106                     e.format(out, Page.getLanguage(req));
107                 }
108
109             } else {
110                 login = "1".equals(req.getParameter("login"));
111                 String hashAlg = req.getParameter("hash_alg");
112                 if (hashAlg != null) {
113                     selectedDigest = Digest.valueOf(hashAlg);
114                 }
115                 if (req.getParameter("CCA") == null) {
116                     outputError(out, req, "You need to accept the CCA.");
117                     return false;
118                 }
119                 System.out.println("issuing " + selectedDigest);
120                 result = new Certificate(LoginPage.getUser(req).getId(), "/commonName=CAcert WoT User", selectedDigest.toString(), this.csr, this.csrType);
121                 try {
122                     result.issue().waitFor(60000);
123                     return true;
124                 } catch (SQLException e) {
125                     e.printStackTrace();
126                 } catch (InterruptedException e) {
127                     e.printStackTrace();
128                 }
129                 return false;
130             }
131         } catch (IOException e) {
132             e.printStackTrace();
133         } catch (GeneralSecurityException e) {
134             e.printStackTrace();
135         }
136         return false;
137     }
138
139     private static void checkSPKAC(String csr, String spkacChallange) throws IOException, GigiApiException {
140         Process p = Runtime.getRuntime().exec(new String[] {
141                 "openssl", "spkac", "-verify"
142         });
143         OutputStream outputStream = p.getOutputStream();
144         outputStream.write(csr.getBytes());
145         outputStream.flush();
146         outputStream.close();
147         BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream(), "UTF-8"));
148         String line;
149         String challenge = null;
150         while ((line = br.readLine()) != null) {
151             line = line.trim();
152             String challengePrefix = "Challenge String: ";
153             if (line.startsWith(challengePrefix)) {
154                 challenge = line.substring(challengePrefix.length());
155             }
156         }
157         GigiApiException gae = new GigiApiException();
158         if ( !spkacChallange.equals(challenge)) {
159             gae.mergeInto(new GigiApiException("The challenge-response code of your certificate request did not match. Can't continue with certificaterequest."));
160         }
161         try {
162             if (p.waitFor() != 0) {
163                 gae.mergeInto(new GigiApiException("The signature of your certificate request is invalid. Can't continue with certificaterequest."));
164             }
165         } catch (InterruptedException e) {
166             e.printStackTrace();
167         }
168         if ( !gae.isEmpty()) {
169             throw gae;
170         }
171     }
172
173     private PKCS10 parseCSR(String csr) throws IOException, GeneralSecurityException {
174         csr = csr.replaceFirst("-----BEGIN (NEW )?CERTIFICATE REQUEST-----", "");
175         csr = csr.replaceFirst("-----END (NEW )?CERTIFICATE REQUEST-----", "");
176         csr = csr.replace("\r", "");
177         csr = csr.replace("\n", "");
178         byte[] b = Base64.getDecoder().decode(csr);
179         // Also checks signature validity
180         return new PKCS10(b);
181     }
182
183     @Override
184     public void output(PrintWriter out, Language l, Map<String, Object> vars) {
185         if (csr == null) {
186             HashMap<String, Object> vars2 = new HashMap<String, Object>(vars);
187             vars2.put("csrf", getCSRFToken());
188             vars2.put("csrf_name", getCsrfFieldName());
189             vars2.put("spkacChallange", spkacChallange);
190             tIni.output(out, l, vars2);
191             return;
192         } else {
193             super.output(out, l, vars);
194         }
195     }
196
197     @Override
198     protected void outputContent(PrintWriter out, Language l, Map<String, Object> vars) {
199         HashMap<String, Object> vars2 = new HashMap<String, Object>(vars);
200         vars2.put("CCA", "<a href='/policy/CAcertCommunityAgreement.html'>CCA</a>");
201
202         final EmailAddress[] ea = u.getEmails();
203         vars2.put("emails", new IterableDataset() {
204
205             int count;
206
207             @Override
208             public boolean next(Language l, Map<String, Object> vars) {
209                 if (count >= ea.length) {
210                     return false;
211                 }
212                 vars.put("id", ea[count].getId());
213                 vars.put("value", ea[count].getAddress());
214                 count++;
215                 return true;
216             }
217         });
218         vars2.put("hashs", new HashAlgorithms(selectedDigest));
219         t.output(out, l, vars2);
220     }
221 }