@Override protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException { response.setHeader("Access-Control-Allow-Origin", "*"); try { if (server == null) { LOG.error("server in servlet not configured"); response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); response.setContentLength(0); return; } ResponderAndRelativeUri r = server.getResponderAndRelativeUri(request); if (r == null) { response.sendError(HttpServletResponse.SC_NOT_FOUND); return; } if (StringUtil.isNotBlank(r.getRelativeUri())) { response.sendError(HttpServletResponse.SC_NOT_FOUND); return; } Responder responder = r.getResponder(); HealthCheckResult healthResult = server.healthCheck(responder); if (healthResult.isHealthy()) { response.setStatus(HttpServletResponse.SC_OK); } else { response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } response.setContentType(HealthCheckServlet.CT_RESPONSE); byte[] respBytes = healthResult.toJsonMessage(true).getBytes(); response.setContentLength(respBytes.length); response.getOutputStream().write(respBytes); } 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"; if (LOG.isErrorEnabled()) { LOG.error(LogUtil.buildExceptionLogFormat(message), t.getClass().getName(), t.getMessage()); } LOG.debug(message, t); response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); response.setContentLength(0); } response.flushBuffer(); } // method doGet
public static void addNamedCurves() { synchronized (EXECUTED) { if (!successful) { LOG.warn("could not initialize"); return; } if (EXECUTED) { return; } EXECUTED = Boolean.TRUE; try { if (jdk18on) { addNamedCurves_jdk18on(); } else { addNamedCurves_jdk17(); } } catch (Throwable t) { final String message = "uncatched Error"; if (LOG.isErrorEnabled()) { LOG.error( LogUtil.buildExceptionLogFormat(message), t.getClass().getName(), t.getMessage()); } LOG.debug(message, t); } } }
private static Field getField(final Class<?> clazz, final String fieldName) { String desc = "Field " + fieldName; try { Field field = clazz.getDeclaredField(fieldName); field.setAccessible(true); return field; } catch (NoSuchFieldException e) { final String message = "could not get " + desc; if (LOG.isWarnEnabled()) { LOG.warn(LogUtil.buildExceptionLogFormat(message), e.getClass().getName(), e.getMessage()); } LOG.debug(message, e); } return null; }
private static Method getMethod( final Class<?> clz, final String methodName, final Class<?>[] params) { Method serviceMethod = null; final String desc = "method " + clz.getName() + "." + methodName; try { if (params == null) { serviceMethod = clz.getDeclaredMethod(methodName); } else { serviceMethod = clz.getDeclaredMethod(methodName, params); } serviceMethod.setAccessible(true); return serviceMethod; } catch (SecurityException | NoSuchMethodException e) { final String message = "could not get " + desc; if (LOG.isWarnEnabled()) { LOG.warn(LogUtil.buildExceptionLogFormat(message), e.getClass().getName(), e.getMessage()); } LOG.debug(message, e); } return null; }
private void initPkcs11ModuleConf() { if (p11Control != null) { return; } if (StringUtil.isBlank(pkcs11ConfFile)) { throw new IllegalStateException("pkcs11ConfFile is not set"); } try { JAXBContext jaxbContext = JAXBContext.newInstance(ObjectFactory.class); Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); SchemaFactory schemaFact = SchemaFactory.newInstance(javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI); Schema schema = schemaFact.newSchema(getClass().getResource("/xsd/pkcs11-conf.xsd")); unmarshaller.setSchema(schema); @SuppressWarnings("unchecked") JAXBElement<PKCS11ConfType> rootElement = (JAXBElement<PKCS11ConfType>) unmarshaller.unmarshal(new File(pkcs11ConfFile)); PKCS11ConfType pkcs11Conf = rootElement.getValue(); ModulesType modulesType = pkcs11Conf.getModules(); Map<String, P11ModuleConf> confs = new HashMap<>(); for (ModuleType moduleType : modulesType.getModule()) { String name = moduleType.getName(); if (DEFAULT_P11MODULE_NAME.equals(name)) { throw new ConfigurationException( "invald module name " + DEFAULT_P11MODULE_NAME + ", it is reserved"); } if (confs.containsKey(name)) { throw new ConfigurationException( "multiple modules with the same module name is not permitted"); } P11PasswordRetriever pwdRetriever; PasswordsType passwordsType = moduleType.getPasswords(); if (passwordsType == null || CollectionUtil.isEmpty(passwordsType.getPassword())) { pwdRetriever = P11NullPasswordRetriever.INSTANCE; } else { pwdRetriever = new P11PasswordRetrieverImpl(); ((P11PasswordRetrieverImpl) pwdRetriever).setPasswordResolver(passwordResolver); for (PasswordType passwordType : passwordsType.getPassword()) { Set<P11SlotIdentifier> slots = getSlots(passwordType.getSlots()); ((P11PasswordRetrieverImpl) pwdRetriever) .addPasswordEntry(slots, new ArrayList<>(passwordType.getSinglePassword())); } } Set<P11SlotIdentifier> includeSlots = getSlots(moduleType.getIncludeSlots()); Set<P11SlotIdentifier> excludeSlots = getSlots(moduleType.getExcludeSlots()); final String osName = System.getProperty("os.name").toLowerCase(); String nativeLibraryPath = null; for (NativeLibraryType library : moduleType.getNativeLibraries().getNativeLibrary()) { List<String> osNames = library.getOs(); if (CollectionUtil.isEmpty(osNames)) { nativeLibraryPath = library.getPath(); } else { for (String entry : osNames) { if (osName.contains(entry.toLowerCase())) { nativeLibraryPath = library.getPath(); break; } } } if (nativeLibraryPath != null) { break; } } if (nativeLibraryPath == null) { throw new ConfigurationException("could not find PKCS#11 library for OS " + osName); } P11ModuleConf conf = new P11ModuleConf(name, nativeLibraryPath, pwdRetriever, includeSlots, excludeSlots); confs.put(name, conf); } final String defaultModuleName = modulesType.getDefaultModule(); if (confs.containsKey(defaultModuleName) == false) { throw new ConfigurationException("default module " + defaultModuleName + " is not defined"); } this.p11Control = new P11Control(defaultModuleName, new HashSet<>(confs.values())); } catch (JAXBException | SAXException | ConfigurationException e) { final String message = "invalid configuration file " + pkcs11ConfFile; if (LOG.isErrorEnabled()) { final String exceptionMessage; if (e instanceof JAXBException) { exceptionMessage = XMLUtil.getMessage((JAXBException) e); } else { exceptionMessage = e.getMessage(); } LOG.error( LogUtil.buildExceptionLogFormat(message), e.getClass().getName(), exceptionMessage); } LOG.debug(message, e); throw new RuntimeException(message); } }
private static void addNamedCurves_jdk18on() { final Class<?>[] Param_CurveDB_add = new Class[] { String.class, String.class, int.class, String.class, String.class, String.class, String.class, String.class, String.class, int.class, Pattern.class }; final Class<?>[] Param_getCurve = new Class[] {String.class}; Method method_add = getMethod(class_CurveDB, "add", Param_CurveDB_add); if (method_add == null) { return; } Method method_getCurve = getMethod(class_CurveDB, "lookup", Param_getCurve); if (method_getCurve == null) { return; } Field field_oidMap = getField(class_CurveDB, "oidMap"); if (field_oidMap == null) { return; } Field field_specCollection = getField(class_CurveDB, "specCollection"); if (field_specCollection == null) { return; } Set<String> processedCurveOids = new HashSet<>(); Map<String, String> addedCurves = new HashMap<>(); Enumeration<?> curveNames = ECNamedCurveTable.getNames(); while (curveNames.hasMoreElements()) { String curveName = (String) curveNames.nextElement(); ASN1ObjectIdentifier curveId = getCurveId(curveName); if (curveId == null) { LOG.debug("cound not find curve OID for curve {}, ignore it", curveName); continue; } String curveDesc = "named curve " + curveName + " (" + curveId + ")"; if (processedCurveOids.contains(curveId.getId())) { LOG.debug("{} is already processed, ignore it", curveDesc); continue; } processedCurveOids.add(curveId.getId()); if (curve_isRegistered(method_getCurve, curveId)) { LOG.info("{} is already registered, ignore it", curveDesc); continue; } X9ECParameters params = ECNamedCurveTable.getByOID(curveId); ECCurve curve = params.getCurve(); if (curve instanceof ECCurve.Fp || curve instanceof ECCurve.F2m) { CurveData c = new CurveData(params); boolean added = CurveDB_add( method_add, curveName, curveId.getId(), c.type, c.sfield, c.a, c.b, c.x, c.y, c.n, c.h); if (added) { LOG.debug("added {}", curveDesc); addedCurves.put(curveName, curveId.getId()); } else { LOG.warn("could not add {}", curveDesc); } } else { LOG.info("unknown curve type {}", curve.getClass().getName()); } } try { Map<?, ?> oidMap = (Map<?, ?>) field_oidMap.get(null); Collection<?> namedCurves = Collections.unmodifiableCollection(oidMap.values()); field_specCollection.set(null, namedCurves); } catch (IllegalArgumentException | IllegalAccessException | ClassCastException e) { final String message = "could not update change the value of field CurveDB.specCollection."; if (LOG.isWarnEnabled()) { LOG.warn(LogUtil.buildExceptionLogFormat(message), e.getClass().getName(), e.getMessage()); } LOG.debug(message, e); } logAddedCurves(addedCurves); }
private static void addNamedCurves_jdk17() { final Class<?>[] Param_NamedCurve_add = new Class[] { String.class, String.class, int.class, String.class, String.class, String.class, String.class, String.class, String.class, int.class }; final Class<?>[] Param_getCurve = new Class[] {String.class}; Method method_add = getMethod(class_NamedCurve, "add", Param_NamedCurve_add); if (method_add == null) { return; } Method method_getCurve = getMethod(class_NamedCurve, "getECParameterSpec", Param_getCurve); if (method_getCurve == null) { return; } Field field_SPLIT_PATTERN = getField(class_NamedCurve, "SPLIT_PATTERN"); if (field_SPLIT_PATTERN == null) { return; } try { field_SPLIT_PATTERN.set(null, SPLIT_PATTERN); } catch (IllegalArgumentException | IllegalAccessException e) { final String message = "could not set Field SPLIT_PATTERN"; if (LOG.isWarnEnabled()) { LOG.warn(LogUtil.buildExceptionLogFormat(message), e.getClass().getName(), e.getMessage()); } LOG.debug(message, e); return; } Set<String> processedCurveOids = new HashSet<>(); Map<String, String> addedCurves = new HashMap<>(); Enumeration<?> curveNames = ECNamedCurveTable.getNames(); while (curveNames.hasMoreElements()) { String curveName = (String) curveNames.nextElement(); ASN1ObjectIdentifier curveId = getCurveId(curveName); if (curveId == null) { LOG.info("cound not find curve OID for curve {}, ignore it", curveName); continue; } String curveDesc = "named curve " + curveName + " (" + curveId + ")"; if (processedCurveOids.contains(curveId.getId())) { LOG.debug("{} is already processed, ignore it", curveDesc); continue; } processedCurveOids.add(curveId.getId()); if (curve_isRegistered(method_getCurve, curveId)) { LOG.debug("{} is already registered, ignore it", curveDesc); continue; } X9ECParameters params = ECNamedCurveTable.getByOID(curveId); ECCurve curve = params.getCurve(); if (curve instanceof ECCurve.Fp || curve instanceof ECCurve.F2m) { CurveData c = new CurveData(params); boolean added = NamedCurve_add( method_add, curveName, curveId.getId(), c.type, c.sfield, c.a, c.b, c.x, c.y, c.n, c.h); if (added) { LOG.debug("added {}", curveDesc); addedCurves.put(curveName, curveId.getId()); } else { LOG.warn("could not add {}", curveDesc); } } else { LOG.info("unknown curve type {}", curve.getClass().getName()); } } try { field_SPLIT_PATTERN.set(null, null); } catch (IllegalArgumentException | IllegalAccessException e) { final String message = "could not set Field SPLIT_PATTERN"; if (LOG.isWarnEnabled()) { LOG.warn(LogUtil.buildExceptionLogFormat(message), e.getClass().getName(), e.getMessage()); } LOG.debug(message, e); return; } logAddedCurves(addedCurves); }
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