protected static final Set getQualifierSet(ASN1Sequence qualifiers)
      throws CertPathValidatorException {
    Set pq = new HashSet();

    if (qualifiers == null) {
      return pq;
    }

    ByteArrayOutputStream bOut = new ByteArrayOutputStream();
    ASN1OutputStream aOut = new ASN1OutputStream(bOut);

    Enumeration e = qualifiers.getObjects();

    while (e.hasMoreElements()) {
      try {
        aOut.writeObject((ASN1Encodable) e.nextElement());

        pq.add(new PolicyQualifierInfo(bOut.toByteArray()));
      } catch (IOException ex) {
        throw new ExtCertPathValidatorException("Policy qualifier info cannot be decoded.", ex);
      }

      bOut.reset();
    }

    return pq;
  }
  public static void writeDHParameters(Writer _out, DHParameterSpec params) throws IOException {
    BufferedWriter out = makeBuffered(_out);
    ByteArrayOutputStream bOut = new ByteArrayOutputStream();
    ASN1OutputStream aOut = new ASN1OutputStream(bOut);

    ASN1EncodableVector v = new ASN1EncodableVector();

    BigInteger value;
    if ((value = params.getP()) != null) {
      v.add(new DERInteger(value));
    }
    if ((value = params.getG()) != null) {
      v.add(new DERInteger(value));
    }

    aOut.writeObject(new DERSequence(v));
    byte[] encoding = bOut.toByteArray();

    out.write(BEF_G + PEM_STRING_DHPARAMS + AFT);
    out.newLine();
    writeEncoded(out, encoding);
    out.write(BEF_E + PEM_STRING_DHPARAMS + AFT);
    out.newLine();
    out.flush();
  }
  public static void writeDSAPrivateKey(
      Writer _out, DSAPrivateKey obj, CipherSpec cipher, char[] passwd) throws IOException {
    BufferedWriter out = makeBuffered(_out);
    PrivateKeyInfo info =
        new PrivateKeyInfo((ASN1Sequence) new ASN1InputStream(getEncoded(obj)).readObject());
    ByteArrayOutputStream bOut = new ByteArrayOutputStream();
    ASN1OutputStream aOut = new ASN1OutputStream(bOut);

    DSAParameter p = DSAParameter.getInstance(info.getAlgorithmId().getParameters());
    ASN1EncodableVector v = new ASN1EncodableVector();
    v.add(new DERInteger(0));
    v.add(new DERInteger(p.getP()));
    v.add(new DERInteger(p.getQ()));
    v.add(new DERInteger(p.getG()));

    BigInteger x = obj.getX();
    BigInteger y = p.getG().modPow(x, p.getP());

    v.add(new DERInteger(y));
    v.add(new DERInteger(x));

    aOut.writeObject(new DERSequence(v));
    byte[] encoding = bOut.toByteArray();

    if (cipher != null && passwd != null) {
      writePemEncrypted(out, PEM_STRING_DSA, encoding, cipher, passwd);
    } else {
      writePemPlain(out, PEM_STRING_DSA, encoding);
    }
  }
  public static void writeRSAPrivateKey(
      Writer _out, RSAPrivateCrtKey obj, CipherSpec cipher, char[] passwd) throws IOException {
    assert (obj != null);
    BufferedWriter out = makeBuffered(_out);
    RSAPrivateKeyStructure keyStruct =
        new RSAPrivateKeyStructure(
            obj.getModulus(),
            obj.getPublicExponent(),
            obj.getPrivateExponent(),
            obj.getPrimeP(),
            obj.getPrimeQ(),
            obj.getPrimeExponentP(),
            obj.getPrimeExponentQ(),
            obj.getCrtCoefficient());

    ByteArrayOutputStream bOut = new ByteArrayOutputStream();
    ASN1OutputStream aOut = new ASN1OutputStream(bOut);
    aOut.writeObject(keyStruct);
    aOut.close();
    byte[] encoding = bOut.toByteArray();

    if (cipher != null && passwd != null) {
      writePemEncrypted(out, PEM_STRING_RSA, encoding, cipher, passwd);
    } else {
      writePemPlain(out, PEM_STRING_RSA, encoding);
    }
  }
  private void processRequest(
      final HttpServletRequest request,
      final HttpServletResponse response,
      final ResponderAndRelativeUri r,
      final boolean getMethod)
      throws ServletException, IOException {
    Responder responder = r.getResponder();
    AuditEvent auditEvent = null;

    AuditLevel auditLevel = AuditLevel.INFO;
    AuditStatus auditStatus = AuditStatus.SUCCESSFUL;
    String auditMessage = null;

    long start = 0;

    AuditService auditService =
        (auditServiceRegister == null) ? null : auditServiceRegister.getAuditService();

    if (auditService != null && responder.getAuditOption() != null) {
      start = System.currentTimeMillis();
      auditEvent = new AuditEvent(new Date());
      auditEvent.setApplicationName("OCSP");
      auditEvent.setName("PERF");
    }

    try {
      if (server == null) {
        String message = "responder in servlet not configured";
        LOG.error(message);
        response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        response.setContentLength(0);

        auditLevel = AuditLevel.ERROR;
        auditStatus = AuditStatus.FAILED;
        auditMessage = message;
        return;
      }

      InputStream requestStream;
      if (getMethod) {
        String relativeUri = r.getRelativeUri();

        // RFC2560 A.1.1 specifies that request longer than 255 bytes SHOULD be sent by
        // POST, we support GET for longer requests anyway.
        if (relativeUri.length() > responder.getRequestOption().getMaxRequestSize()) {
          response.setContentLength(0);
          response.setStatus(HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE);

          auditStatus = AuditStatus.FAILED;
          auditMessage = "request too large";
          return;
        }

        requestStream = new ByteArrayInputStream(Base64.decode(relativeUri));
      } else {
        // accept only "application/ocsp-request" as content type
        if (!CT_REQUEST.equalsIgnoreCase(request.getContentType())) {
          response.setContentLength(0);
          response.setStatus(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE);

          auditStatus = AuditStatus.FAILED;
          auditMessage = "unsupporte media type " + request.getContentType();
          return;
        }

        // request too long
        if (request.getContentLength() > responder.getRequestOption().getMaxRequestSize()) {
          response.setContentLength(0);
          response.setStatus(HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE);

          auditStatus = AuditStatus.FAILED;
          auditMessage = "request too large";
          return;
        } // if (CT_REQUEST)

        requestStream = request.getInputStream();
      } // end if (getMethod)

      OCSPRequest ocspRequest;
      try {
        ASN1StreamParser parser = new ASN1StreamParser(requestStream);
        ocspRequest = OCSPRequest.getInstance(parser.readObject());
      } catch (Exception e) {
        response.setContentLength(0);
        response.setStatus(HttpServletResponse.SC_BAD_REQUEST);

        auditStatus = AuditStatus.FAILED;
        auditMessage = "bad request";

        final String message = "could not parse the request (OCSPRequest)";
        if (LOG.isErrorEnabled()) {
          LOG.error(
              LogUtil.buildExceptionLogFormat(message), e.getClass().getName(), e.getMessage());
        }
        LOG.debug(message, e);

        return;
      }

      OCSPReq ocspReq = new OCSPReq(ocspRequest);

      response.setContentType(HttpOcspServlet.CT_RESPONSE);

      OcspRespWithCacheInfo ocspRespWithCacheInfo =
          server.answer(responder, ocspReq, auditEvent, getMethod);
      if (ocspRespWithCacheInfo == null) {
        auditMessage = "processRequest returned null, this should not happen";
        LOG.error(auditMessage);
        response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        response.setContentLength(0);

        auditLevel = AuditLevel.ERROR;
        auditStatus = AuditStatus.FAILED;
      } else {
        OCSPResp resp = ocspRespWithCacheInfo.getResponse();
        byte[] encodedOcspResp = null;
        response.setStatus(HttpServletResponse.SC_OK);

        ResponseCacheInfo cacheInfo = ocspRespWithCacheInfo.getCacheInfo();
        if (getMethod && cacheInfo != null) {
          encodedOcspResp = resp.getEncoded();
          long now = System.currentTimeMillis();
          // RFC 5019 6.2: Date: The date and time at which the OCSP server generated
          // the HTTP response.
          response.setDateHeader("Date", now);
          // RFC 5019 6.2: Last-Modified: date and time at which the OCSP responder
          // last modified the response.
          response.setDateHeader("Last-Modified", cacheInfo.getThisUpdate());
          // RFC 5019 6.2: Expires: This date and time will be the same as the
          // nextUpdate time-stamp in the OCSP
          // response itself.
          // This is overridden by max-age on HTTP/1.1 compatible components
          if (cacheInfo.getNextUpdate() != null) {
            response.setDateHeader("Expires", cacheInfo.getNextUpdate());
          }
          // RFC 5019 6.2: This profile RECOMMENDS that the ETag value be the ASCII
          // HEX representation of the SHA1 hash of the OCSPResponse structure.
          response.setHeader(
              "ETag",
              new StringBuilder(42)
                  .append('\\')
                  .append(HashCalculator.hexSha1(encodedOcspResp))
                  .append('\\')
                  .toString());

          // Max age must be in seconds in the cache-control header
          long maxAge;
          if (responder.getResponseOption().getCacheMaxAge() != null) {
            maxAge = responder.getResponseOption().getCacheMaxAge().longValue();
          } else {
            maxAge = OcspServer.defaultCacheMaxAge;
          }

          if (cacheInfo.getNextUpdate() != null) {
            maxAge =
                Math.min(maxAge, (cacheInfo.getNextUpdate() - cacheInfo.getThisUpdate()) / 1000);
          }

          response.setHeader(
              "Cache-Control",
              new StringBuilder(55)
                  .append("max-age=")
                  .append(maxAge)
                  .append(",public,no-transform,must-revalidate")
                  .toString());
        } // end if (getMethod && cacheInfo != null)

        if (encodedOcspResp != null) {
          response.getOutputStream().write(encodedOcspResp);
        } else {
          ASN1OutputStream asn1Out = new ASN1OutputStream(response.getOutputStream());
          asn1Out.writeObject(resp.toASN1Structure());
          asn1Out.flush();
        }
      } // end if (ocspRespWithCacheInfo)
    } catch (EOFException e) {
      final String message = "Connection reset by peer";
      if (LOG.isErrorEnabled()) {
        LOG.warn(LogUtil.buildExceptionLogFormat(message), e.getClass().getName(), e.getMessage());
      }
      LOG.debug(message, e);

      response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
      response.setContentLength(0);
    } catch (Throwable t) {
      final String message = "Throwable thrown, this should not happen!";
      LOG.error(message, t);

      response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
      response.setContentLength(0);

      auditLevel = AuditLevel.ERROR;
      auditStatus = AuditStatus.FAILED;
      auditMessage = "internal error";
    } finally {
      try {
        response.flushBuffer();
      } finally {
        if (auditEvent != null) {
          if (auditLevel != null) {
            auditEvent.setLevel(auditLevel);
          }

          if (auditStatus != null) {
            auditEvent.setStatus(auditStatus);
          }

          if (auditMessage != null) {
            auditEvent.addEventData(new AuditEventData("message", auditMessage));
          }

          auditEvent.setDuration(System.currentTimeMillis() - start);

          if (!auditEvent.containsChildAuditEvents()) {
            auditService.logEvent(auditEvent);
          } else {
            List<AuditEvent> expandedAuditEvents = auditEvent.expandAuditEvents();
            for (AuditEvent event : expandedAuditEvents) {
              auditService.logEvent(event);
            }
          }
        } // end if (auditEvent != null)
      } // end inner try
    } // end external try
  } // method processRequest