upd: for installation send certificate chains as p7 encoded cert set
[gigi.git] / src / org / cacert / gigi / pages / account / certs / Certificates.java
1 package org.cacert.gigi.pages.account.certs;
2
3 import java.io.IOException;
4 import java.io.PrintWriter;
5 import java.net.URLEncoder;
6 import java.security.GeneralSecurityException;
7 import java.security.cert.X509Certificate;
8 import java.util.HashMap;
9 import java.util.LinkedList;
10 import java.util.Map;
11
12 import javax.servlet.ServletOutputStream;
13 import javax.servlet.http.HttpServletRequest;
14 import javax.servlet.http.HttpServletResponse;
15
16 import org.cacert.gigi.dbObjects.CACertificate;
17 import org.cacert.gigi.dbObjects.Certificate;
18 import org.cacert.gigi.localisation.Language;
19 import org.cacert.gigi.output.template.Form;
20 import org.cacert.gigi.output.template.IterableDataset;
21 import org.cacert.gigi.output.template.Template;
22 import org.cacert.gigi.pages.HandlesMixedRequest;
23 import org.cacert.gigi.pages.LoginPage;
24 import org.cacert.gigi.pages.Page;
25 import org.cacert.gigi.util.PEM;
26
27 import sun.security.pkcs.ContentInfo;
28 import sun.security.pkcs.PKCS7;
29 import sun.security.pkcs.SignerInfo;
30 import sun.security.x509.AlgorithmId;
31
32 public class Certificates extends Page implements HandlesMixedRequest {
33
34     private Template certDisplay = new Template(Certificates.class.getResource("CertificateDisplay.templ"));
35
36     public static final String PATH = "/account/certs";
37
38     static class TrustchainIterable implements IterableDataset {
39
40         CACertificate cert;
41
42         public TrustchainIterable(CACertificate cert) {
43             this.cert = cert;
44         }
45
46         @Override
47         public boolean next(Language l, Map<String, Object> vars) {
48             if (cert == null) {
49                 return false;
50             }
51             vars.put("name", cert.getKeyname());
52             vars.put("link", cert.getLink());
53             if (cert.isSelfsigned()) {
54                 cert = null;
55                 return true;
56             }
57             cert = cert.getParent();
58             return true;
59         }
60
61     }
62
63     public Certificates() {
64         super("Certificates");
65     }
66
67     @Override
68     public boolean beforeTemplate(HttpServletRequest req, HttpServletResponse resp) throws IOException {
69
70         String pi = req.getPathInfo().substring(PATH.length());
71         if (pi.length() == 0) {
72             return false;
73         }
74         pi = pi.substring(1);
75         boolean crt = false;
76         boolean cer = false;
77         resp.setContentType("application/pkix-cert");
78         if (req.getParameter("install") != null) {
79             resp.setContentType("application/x-x509-user-cert");
80         }
81         if (pi.endsWith(".crt")) {
82             crt = true;
83             pi = pi.substring(0, pi.length() - 4);
84         } else if (pi.endsWith(".cer")) {
85             cer = true;
86             pi = pi.substring(0, pi.length() - 4);
87         } else if (pi.endsWith(".cer")) {
88             cer = true;
89             pi = pi.substring(0, pi.length() - 4);
90         }
91         String serial = pi;
92         try {
93             Certificate c = Certificate.getBySerial(serial);
94             if (c == null || LoginPage.getAuthorizationContext(req).getTarget().getId() != c.getOwner().getId()) {
95                 resp.sendError(404);
96                 return true;
97             }
98             X509Certificate cert = c.cert();
99             if ( !crt && !cer) {
100                 return false;
101             }
102             ServletOutputStream out = resp.getOutputStream();
103             if (crt) {
104                 out.println(PEM.encode("CERTIFICATE", cert.getEncoded()));
105                 if (req.getParameter("chain") != null) {
106                     CACertificate ca = c.getParent();
107                     while ( !ca.isSelfsigned()) {
108                         out.println(PEM.encode("CERTIFICATE", ca.getCertificate().getEncoded()));
109                         ca = ca.getParent();
110                     }
111                     if (req.getParameter("noAnchor") == null) {
112                         out.println(PEM.encode("CERTIFICATE", ca.getCertificate().getEncoded()));
113                     }
114                 }
115             } else if (cer) {
116                 if (req.getParameter("install") != null) {
117                     PKCS7 p7 = toP7Chain(c);
118                     p7.encodeSignedData(out);
119                     /*
120                      * ContentInfo ci = toCIChain(c); try (DerOutputStream dos =
121                      * new DerOutputStream()) { ci.encode(dos);
122                      * out.write(dos.toByteArray()); }
123                      */
124                 } else {
125                     out.write(cert.getEncoded());
126                 }
127             }
128         } catch (IllegalArgumentException e) {
129             resp.sendError(404);
130             return true;
131         } catch (GeneralSecurityException e) {
132             resp.sendError(404);
133             return true;
134         }
135
136         return true;
137     }
138
139     private static PKCS7 toP7Chain(Certificate c) throws IOException, GeneralSecurityException {
140         LinkedList<X509Certificate> ll = getChain(c);
141         PKCS7 p7 = new PKCS7(new AlgorithmId[0], new ContentInfo(ContentInfo.DATA_OID, null), ll.toArray(new X509Certificate[ll.size()]), new SignerInfo[0]);
142         return p7;
143     }
144
145     private static LinkedList<X509Certificate> getChain(Certificate c) throws IOException, GeneralSecurityException {
146         LinkedList<X509Certificate> ll = new LinkedList<>();
147         ll.add(c.cert());
148         CACertificate ca = c.getParent();
149         while ( !ca.isSelfsigned()) {
150             ll.add(ca.getCertificate());
151             ca = ca.getParent();
152         }
153         ll.add(ca.getCertificate());
154         return ll;
155     }
156
157     @Override
158     public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
159         if (req.getQueryString() != null && !req.getQueryString().equals("") && !req.getQueryString().equals("withRevoked")) {
160             return;// Block actions by get parameters.
161         }
162         if ( !req.getPathInfo().equals(PATH)) {
163             resp.sendError(500);
164             return;
165         }
166         Form.getForm(req, CertificateModificationForm.class).submit(resp.getWriter(), req);
167         doGet(req, resp);
168     }
169
170     @Override
171     public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
172         PrintWriter out = resp.getWriter();
173         String pi = req.getPathInfo().substring(PATH.length());
174         if (pi.length() != 0) {
175             pi = pi.substring(1);
176
177             String serial = pi;
178             Certificate c = Certificate.getBySerial(serial);
179             if (c == null || LoginPage.getAuthorizationContext(req).getTarget().getId() != c.getOwner().getId()) {
180                 resp.sendError(404);
181                 return;
182             }
183             HashMap<String, Object> vars = new HashMap<>();
184             vars.put("serial", URLEncoder.encode(serial, "UTF-8"));
185             vars.put("trustchain", new TrustchainIterable(c.getParent()));
186             try {
187                 vars.put("cert", c.cert());
188             } catch (GeneralSecurityException e) {
189                 e.printStackTrace();
190             }
191             certDisplay.output(out, getLanguage(req), vars);
192
193             return;
194         }
195
196         HashMap<String, Object> vars = new HashMap<String, Object>();
197         new CertificateModificationForm(req, req.getParameter("withRevoked") != null).output(out, getLanguage(req), vars);
198     }
199
200 }