--- java/org/apache/catalina/core/AprLifecycleListener.java (revision 1579025) +++ java/org/apache/catalina/core/AprLifecycleListener.java (working copy) @@ -57,9 +57,9 @@ protected static final int TCN_REQUIRED_MAJOR = 1; protected static final int TCN_REQUIRED_MINOR = 1; - protected static final int TCN_REQUIRED_PATCH = 29; + protected static final int TCN_REQUIRED_PATCH = 30; protected static final int TCN_RECOMMENDED_MINOR = 1; - protected static final int TCN_RECOMMENDED_PV = 29; + protected static final int TCN_RECOMMENDED_PV = 30; // ---------------------------------------------- Properties @@ -70,6 +70,18 @@ protected static boolean aprInitialized = false; protected static boolean aprAvailable = false; protected static boolean fipsModeActive = false; + /** + * FIPS_mode documentation states that the return value will be + * whatever value was originally passed-in to FIPS_mode_set(). + * FIPS_mode_set docs say the argument should be non-zero to enter + * FIPS mode, and that upon success, the return value will be the + * same as the argument passed-in. Docs also highly recommend + * that the value "1" be used "to avoid compatibility issues". + * In order to avoid the argument and check-value from getting out + * of sync for some reason, we are using the class constant + * FIPS_ON here. + */ + private static final int FIPS_ON = 1; protected static final Object lock = new Object(); @@ -110,7 +122,7 @@ } } // Failure to initialize FIPS mode is fatal - if ("on".equalsIgnoreCase(FIPSMode) && !isFIPSModeActive()) { + if (!(null == FIPSMode || "off".equalsIgnoreCase(FIPSMode)) && !isFIPSModeActive()) { Error e = new Error( sm.getString("aprListener.initializeFIPSFailed")); // Log here, because thrown error might be not logged @@ -252,13 +264,59 @@ method = clazz.getMethod(methodName, paramTypes); method.invoke(null, paramValues); - if("on".equalsIgnoreCase(FIPSMode)) { + final boolean enterFipsMode; + + if("on".equalsIgnoreCase(FIPSMode) + || "require".equalsIgnoreCase(FIPSMode)) { + // FIPS_mode documentation states that the return value will be + // whatever value was originally passed-in to FIPS_mode_set(). + // FIPS_mode_set docs say the argument should be non-zero to enter + // FIPS mode, and that upon success, the return value will be the + // same as the argument passed-in. Docs also highly recommend + // that the value "1" be used "to avoid compatibility issues". + // In order to avoid the argument and check-value from getting out + // of sync for some reason, we are using the class constant + // FIPS_ON here. + final int fipsModeState = SSL.fipsModeGet(); + + if(log.isDebugEnabled()) + log.debug(sm.getString("aprListener.currentFIPSMode", + Integer.valueOf(fipsModeState))); + + // Return values: 0=Not in FIPS mode, 1=In FIPS mode, + // exception if FIPS totally unavailable + enterFipsMode = 1 != fipsModeState; + + if("on".equalsIgnoreCase(FIPSMode)) { + if(!enterFipsMode) + log.info(sm.getString("aprListener.skipFIPSInitialization")); + } else if("require".equalsIgnoreCase(FIPSMode)) { + if(enterFipsMode) { + String message = sm.getString("aprListener.alreadyInFIPSMode"); + log.error(message); + throw new IllegalStateException(message); + } + } + } + else if("enter".equalsIgnoreCase(FIPSMode)) { + enterFipsMode = true; + } else + enterFipsMode = false; + + if(enterFipsMode) { log.info(sm.getString("aprListener.initializingFIPS")); - int result = SSL.fipsModeSet(1); + // FIPS_mode_set docs say the argument should be non-zero to enter + // FIPS mode, and that upon success, the return value will be the + // same as the argument passed-in. Docs also highly recommend + // that the value "1" be used "to avoid compatibility issues". + // In order to avoid the argument and check-value from getting out + // of sync for some reason, we are using the class constant + // FIPS_ON here. + final int result = SSL.fipsModeSet(FIPS_ON); - // success is defined as return value = 1 - if(1 == result) { + // success is defined as return value = last argument to FIPS_mode_set() + if(FIPS_ON == result) { fipsModeActive = true; log.info(sm.getString("aprListener.initializeFIPSSuccess")); --- java/org/apache/catalina/core/LocalStrings.properties (revision 1579025) +++ java/org/apache/catalina/core/LocalStrings.properties (working copy) @@ -57,6 +57,9 @@ aprListener.sslInit=Failed to initialize the SSLEngine. aprListener.tcnValid=Loaded APR based Apache Tomcat Native library {0} using APR version {1}. aprListener.flags=APR capabilities: IPv6 [{0}], sendfile [{1}], accept filters [{2}], random [{3}]. +aprListener.currentFIPSMode=Current FIPS mode: {0} +aprListener.skipFIPSInitialization=Already in FIPS mode; skipping FIPS initialization. +aprListener.alreadyInFIPSMode=AprLifecycleListener requested to force entering FIPS mode, but FIPS mode was already enabled. aprListener.initializingFIPS=Initializing FIPS mode... aprListener.initializeFIPSSuccess=Successfully entered FIPS mode aprListener.initializeFIPSFailed=Failed to enter FIPS mode --- java/org/apache/tomcat/jni/SSL.java (revision 1579025) +++ java/org/apache/tomcat/jni/SSL.java (working copy) @@ -230,6 +230,14 @@ public static native int initialize(String engine); /** + * Get the status of FIPS Mode. + * + * @return 0 If OpenSSL is not in FIPS mode, 1 if OpenSSL is in FIPS Mode. + * @throws Exception If tcnative was not compiled with FIPS Mode available. + */ + public static native int fipsModeGet(); + + /** * Enable/Disable FIPS Mode. * * @param mode 1 - enable, 0 - disable --- webapps/docs/config/listeners.xml (revision 1579025) +++ webapps/docs/config/listeners.xml (working copy) @@ -112,12 +112,22 @@ -

Set to on to instruct OpenSSL to go into FIPS mode. +

Set to on to request that OpenSSL be in FIPS mode + (if OpenSSL is already in FIPS mode, it will remain in FIPS mode). + Set to enter to force OpenSSL to enter FIPS mode (an error + will occur if OpenSSL is already in FIPS mode). + Set to require to require that OpenSSL already be + in FIPS mode (an error will occur if OpenSSL is not already in FIPS + mode). FIPS mode requires you to have a FIPS-capable OpenSSL library which you must build yourself. - FIPS mode also requires Tomcat native library version 1.1.23 or later, - which must be built against the FIPS-compatible OpenSSL library. - If this attribute is "on", SSLEngine must be enabled as well. + FIPSMode="on" or FIPSMode="require" requires + Tomcat native library version 1.1.30 or later, while + FIPSMode="enter" can probably be done with Tomcat native + library version 1.2.23 or later -- either of which must be built + against the FIPS-compatible OpenSSL library. + If this attribute is set to any of the above values, SSLEngine + must be enabled as well for any effect. The default value is off.