1 package club.wpia.gigi.ocsp;
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;
12 import java.util.logging.Logger;
14 import javax.servlet.ServletException;
15 import javax.servlet.http.HttpServlet;
16 import javax.servlet.http.HttpServletRequest;
17 import javax.servlet.http.HttpServletResponse;
19 import org.eclipse.jetty.http.HttpMethod;
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;
30 * This is the entry point for OCSP Issuing
32 public class OCSPResponder extends HttpServlet {
34 static final Logger log = Logger.getLogger(OCSPResponder.class.getName());
36 private static final long serialVersionUID = 1L;
38 private final OCSPIssuerManager mgm = new OCSPIssuerManager();
40 public OCSPResponder() {}
42 public static byte[] calcKeyHash(X509Certificate x, MessageDigest md) {
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) {
54 public void init() throws ServletException {
56 new Thread(mgm).start();
60 protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
61 try (Link l = DatabaseConnection.newLink(true)) {
63 if (req.getMethod().equals(HttpMethod.POST.toString())) {
64 bytes = getBytes(req);
67 resp.getWriter().println("OCSP request too large");
71 bytes = Base64.getDecoder().decode(req.getPathInfo().substring(1));
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) {
79 } catch (InterruptedException e1) {
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();
95 CertId id = ids.get(0);
96 OCSPIssuerId iid = new OCSPIssuerId(id);
97 Map<OCSPIssuerId, OCSPIssuer> m0;
98 m0 = mgm.get(iid.getAlg());
100 log.warning("Algorithm " + iid.getAlg() + " not indexed.");
101 return OCSPResponse.invalid();
103 OCSPIssuer iss = m0.get(iid);
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));
112 return OCSPResponse.invalid();
114 return iss.respondBytes(or, id);
117 private byte[] getBytes(HttpServletRequest req) throws IOException {
118 InputStream i = req.getInputStream();
119 ByteArrayOutputStream o = new ByteArrayOutputStream();
120 byte[] buf = new byte[1024];
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
129 byte[] dat = o.toByteArray();