1 package org.cacert.gigi.pages.account;
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.HashMap;
17 import javax.servlet.http.HttpServletRequest;
19 import org.cacert.gigi.Certificate;
20 import org.cacert.gigi.Digest;
21 import org.cacert.gigi.EmailAddress;
22 import org.cacert.gigi.GigiApiException;
23 import org.cacert.gigi.Language;
24 import org.cacert.gigi.User;
25 import org.cacert.gigi.Certificate.CSRType;
26 import org.cacert.gigi.output.Form;
27 import org.cacert.gigi.output.template.HashAlgorithms;
28 import org.cacert.gigi.output.template.IterableDataset;
29 import org.cacert.gigi.output.template.Template;
30 import org.cacert.gigi.pages.LoginPage;
31 import org.cacert.gigi.pages.Page;
32 import org.cacert.gigi.util.PEM;
33 import org.cacert.gigi.util.RandomToken;
35 import sun.security.pkcs10.PKCS10;
38 * This class represents a form that is used for issuing certificates. This
39 * class uses "sun.security" and therefore needs "-XDignore.symbol.file"
41 public class IssueCertificateForm extends Form {
45 Digest selectedDigest = Digest.getDefault();
51 private final static Template t = new Template(IssueCertificateForm.class.getResource("IssueCertificateForm.templ"));
53 private final static Template tIni = new Template(MailCertificateAdd.class.getResource("RequestCertificate.templ"));
55 String spkacChallange;
57 public IssueCertificateForm(HttpServletRequest hsr) {
59 u = LoginPage.getUser(hsr);
60 spkacChallange = RandomToken.generateToken(16);
65 private CSRType csrType;
67 public Certificate getResult() {
72 public boolean submit(PrintWriter out, HttpServletRequest req) {
73 String csr = req.getParameter("CSR");
74 String spkac = req.getParameter("SPKAC");
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());
96 out.println("<br/>digest: sha256<br/>");
98 this.csrType = CSRType.CSR;
99 } else if (spkac != null) {
100 String cleanedSPKAC = "SPKAC=" + spkac.replaceAll("[\r\n]", "");
102 checkSPKAC(cleanedSPKAC, spkacChallange);
103 this.csr = cleanedSPKAC;
104 this.csrType = CSRType.SPKAC;
105 } catch (GigiApiException e) {
106 e.format(out, Page.getLanguage(req));
110 login = "1".equals(req.getParameter("login"));
111 String hashAlg = req.getParameter("hash_alg");
112 if (hashAlg != null) {
113 selectedDigest = Digest.valueOf(hashAlg);
115 if (req.getParameter("CCA") == null) {
116 outputError(out, req, "You need to accept the CCA.");
119 System.out.println("issuing " + selectedDigest);
120 result = new Certificate(LoginPage.getUser(req).getId(), "/commonName=CAcert WoT User", selectedDigest.toString(), this.csr, this.csrType);
122 result.issue().waitFor(60000);
124 } catch (SQLException e) {
126 } catch (InterruptedException e) {
131 } catch (IOException e) {
133 } catch (GeneralSecurityException e) {
139 private static void checkSPKAC(String csr, String spkacChallange) throws IOException, GigiApiException {
140 Process p = Runtime.getRuntime().exec(new String[] {
141 "openssl", "spkac", "-verify"
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"));
149 String challenge = null;
150 while ((line = br.readLine()) != null) {
152 String challengePrefix = "Challenge String: ";
153 if (line.startsWith(challengePrefix)) {
154 challenge = line.substring(challengePrefix.length());
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."));
162 if (p.waitFor() != 0) {
163 gae.mergeInto(new GigiApiException("The signature of your certificate request is invalid. Can't continue with certificaterequest."));
165 } catch (InterruptedException e) {
168 if ( !gae.isEmpty()) {
173 private PKCS10 parseCSR(String csr) throws IOException, GeneralSecurityException {
174 return new PKCS10(PEM.decode("(NEW )?CERTIFICATE REQUEST", csr));
178 public void output(PrintWriter out, Language l, Map<String, Object> vars) {
180 HashMap<String, Object> vars2 = new HashMap<String, Object>(vars);
181 vars2.put("csrf", getCSRFToken());
182 vars2.put("csrf_name", getCsrfFieldName());
183 vars2.put("spkacChallange", spkacChallange);
184 tIni.output(out, l, vars2);
187 super.output(out, l, vars);
192 protected void outputContent(PrintWriter out, Language l, Map<String, Object> vars) {
193 HashMap<String, Object> vars2 = new HashMap<String, Object>(vars);
194 vars2.put("CCA", "<a href='/policy/CAcertCommunityAgreement.html'>CCA</a>");
196 final EmailAddress[] ea = u.getEmails();
197 vars2.put("emails", new IterableDataset() {
202 public boolean next(Language l, Map<String, Object> vars) {
203 if (count >= ea.length) {
206 vars.put("id", ea[count].getId());
207 vars.put("value", ea[count].getAddress());
212 vars2.put("hashs", new HashAlgorithms(selectedDigest));
213 t.output(out, l, vars2);