]> WPIA git - gigi.git/blob - src/club/wpia/gigi/ocsp/OCSPResponder.java
add: implement OCSP serving
[gigi.git] / src / club / wpia / gigi / ocsp / OCSPResponder.java
1 package club.wpia.gigi.ocsp;
2
3 import java.io.ByteArrayOutputStream;
4 import java.io.IOException;
5 import java.io.InputStream;
6 import java.security.GeneralSecurityException;
7 import java.security.MessageDigest;
8 import java.security.cert.X509Certificate;
9 import java.util.Base64;
10 import java.util.List;
11 import java.util.Map;
12 import java.util.logging.Logger;
13
14 import javax.servlet.ServletException;
15 import javax.servlet.http.HttpServlet;
16 import javax.servlet.http.HttpServletRequest;
17 import javax.servlet.http.HttpServletResponse;
18
19 import org.eclipse.jetty.http.HttpMethod;
20
21 import club.wpia.gigi.crypto.OCSPRequest;
22 import club.wpia.gigi.crypto.OCSPResponse;
23 import club.wpia.gigi.database.DatabaseConnection;
24 import club.wpia.gigi.database.DatabaseConnection.Link;
25 import sun.security.provider.certpath.CertId;
26 import sun.security.util.DerInputStream;
27 import sun.security.util.DerValue;
28
29 /**
30  * This is the entry point for OCSP Issuing
31  */
32 public class OCSPResponder extends HttpServlet {
33
34     static final Logger log = Logger.getLogger(OCSPResponder.class.getName());
35
36     private static final long serialVersionUID = 1L;
37
38     private final OCSPIssuerManager mgm = new OCSPIssuerManager();
39
40     public OCSPResponder() {}
41
42     public static byte[] calcKeyHash(X509Certificate x, MessageDigest md) {
43         try {
44             DerInputStream dis = new DerInputStream(x.getPublicKey().getEncoded());
45             DerValue[] seq = dis.getSequence(2);
46             byte[] bitString = seq[1].getBitString();
47             return md.digest(bitString);
48         } catch (IOException e) {
49             throw new Error(e);
50         }
51     }
52
53     @Override
54     public void init() throws ServletException {
55         super.init();
56         new Thread(mgm).start();
57     }
58
59     @Override
60     protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
61         try (Link l = DatabaseConnection.newLink(true)) {
62             byte[] bytes;
63             if (req.getMethod().equals(HttpMethod.POST.toString())) {
64                 bytes = getBytes(req);
65                 if (bytes == null) {
66                     resp.sendError(500);
67                     resp.getWriter().println("OCSP request too large");
68                     return;
69                 }
70             } else {
71                 bytes = Base64.getDecoder().decode(req.getPathInfo().substring(1));
72             }
73             OCSPRequest or = new OCSPRequest(bytes);
74             byte[] res = respond(or);
75             resp.setContentType("application/ocsp-response");
76             resp.getOutputStream().write(res);
77         } catch (GeneralSecurityException e) {
78             e.printStackTrace();
79         } catch (InterruptedException e1) {
80             e1.printStackTrace();
81         }
82     }
83
84     private byte[] respond(OCSPRequest or) throws GeneralSecurityException, IOException {
85         List<CertId> ids = or.getCertIds();
86         if (ids.size() != 1) {
87             // We don't implement multi-requests as:
88             // a) we don't know of applications using them
89             // b) this will introduce additional complexity
90             // c) there is at least one corner-case that needs to be thought of:
91             // an OCSP request might contain requests for certs from different
92             // issuers, what issuer's ocsp cert should sign the response?
93             return OCSPResponse.invalid();
94         }
95         CertId id = ids.get(0);
96         OCSPIssuerId iid = new OCSPIssuerId(id);
97         Map<OCSPIssuerId, OCSPIssuer> m0;
98         m0 = mgm.get(iid.getAlg());
99         if (m0 == null) {
100             log.warning("Algorithm " + iid.getAlg() + " not indexed.");
101             return OCSPResponse.invalid();
102         }
103         OCSPIssuer iss = m0.get(iid);
104
105         if (iss == null) {
106             log.warning("CertID not handled:\n" +//
107                     Base64.getEncoder().encodeToString(id.getIssuerNameHash()) + "\n"//
108                     + Base64.getEncoder().encodeToString(id.getIssuerKeyHash()) + "\n" //
109                     + id.getHashAlgorithm() + "\n"//
110                     + id.getSerialNumber().toString(16));
111
112             return OCSPResponse.invalid();
113         }
114         return iss.respondBytes(or, id);
115     }
116
117     private byte[] getBytes(HttpServletRequest req) throws IOException {
118         InputStream i = req.getInputStream();
119         ByteArrayOutputStream o = new ByteArrayOutputStream();
120         byte[] buf = new byte[1024];
121         int len;
122         while ((len = i.read(buf)) > 0) {
123             o.write(buf, 0, len);
124             if (o.size() > 64 * 1024) {
125                 // for now have 64k as maximum
126                 return null;
127             }
128         }
129         byte[] dat = o.toByteArray();
130         return dat;
131     }
132
133 }