Index: src/org/apache/tomcat/util/net/jss/JSSSocketFactory.java
===================================================================
--- src/org/apache/tomcat/util/net/jss/JSSSocketFactory.java (revision 294)
+++ src/org/apache/tomcat/util/net/jss/JSSSocketFactory.java (revision 297)
@@ -12,7 +12,7 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
+ *
* Copyright (C) 2007 Red Hat, Inc.
* All rights reserved.
* END COPYRIGHT BLOCK */
@@ -29,6 +29,7 @@
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
+import java.security.GeneralSecurityException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
@@ -39,13 +40,20 @@
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
+import org.apache.commons.lang.StringUtils;
// Imports required to "implement" Tomcat 7 Interface
import org.apache.tomcat.util.net.AbstractEndpoint;
+import org.mozilla.jss.CertDatabaseException;
import org.mozilla.jss.CryptoManager;
+import org.mozilla.jss.CryptoManager.NotInitializedException;
+import org.mozilla.jss.KeyDatabaseException;
+import org.mozilla.jss.NoSuchTokenException;
import org.mozilla.jss.crypto.AlreadyInitializedException;
import org.mozilla.jss.crypto.CryptoToken;
+import org.mozilla.jss.crypto.TokenException;
import org.mozilla.jss.ssl.SSLServerSocket;
import org.mozilla.jss.ssl.SSLSocket;
+import org.mozilla.jss.util.IncorrectPasswordException;
import org.mozilla.jss.util.Password;
public class JSSSocketFactory implements
@@ -322,6 +330,7 @@
boolean debug = false;
private IPasswordStore mPasswordStore = null;
private boolean mStrictCiphers = false;
+ private static final int MAX_PW_ATTEMPTS = 3;
public JSSSocketFactory(AbstractEndpoint endpoint) {
this.endpoint = endpoint;
@@ -336,8 +345,8 @@
}
public void setSSLCiphers(String attr) throws SocketException, IOException {
- String ciphers = (String) endpoint.getAttribute(attr);
- if (ciphers == null || ciphers.equals("")) {
+ String ciphers = getEndpointAttribute(attr);
+ if (StringUtils.isEmpty(ciphers)) {
debugWrite("JSSSocketFactory setSSLCiphers: " + attr + " not found");
return;
}
@@ -409,7 +418,11 @@
* parameter is ignored.
*/
public void setSSLOptions() throws SocketException, IOException {
- String options = (String) endpoint.getAttribute("sslOptions");
+ String options = getEndpointAttribute("sslOptions");
+ if (StringUtils.isEmpty(options)) {
+ debugWrite("no sslOptions specified");
+ return;
+ }
StringTokenizer st = new StringTokenizer(options, ",");
while (st.hasMoreTokens()) {
String option = st.nextToken();
@@ -460,10 +473,10 @@
/*
* setSSLVersionRangeDefault sets the range of allowed ssl versions. This
* replaces the obsolete SSL_Option* API
- *
+ *
* @param protoVariant indicates whether this setting is for type "stream"
* or "datagram"
- *
+ *
* @param sslVersionRange_s takes on the form of "min:max" where min/max
* values can be "ssl3, tls1_0, tls1_1, or tls1_2" ssl2 is not supported for
* tomcatjss via this interface The format is "sslVersionRange=min:max"
@@ -516,105 +529,54 @@
return -1;
}
- void init() throws IOException {
+ String getEndpointAttribute(String tag) {
try {
- String deb = (String) endpoint.getAttribute("debug");
- if (deb.equals("true")) {
- debug = true;
- debugFile = new FileWriter("/tmp/tomcatjss.log", true);
- debugWrite("JSSSocketFactory init - debug is on\n");
- }
+ return (String) endpoint.getAttribute(tag);
} catch (Exception e) {
- // System.out.println("no tomcatjss debugging");
+ // old tomcat throws an exception if the parameter does not exist
}
+ return null;
+ }
- try {
- try {
- mPwdPath = (String) endpoint.getAttribute("passwordFile");
- mPwdClass = (String) endpoint.getAttribute("passwordClass");
- if (mPwdClass != null) {
- mPasswordStore = (IPasswordStore) Class.forName(mPwdClass)
- .newInstance();
- mPasswordStore.init(mPwdPath);
- debugWrite("JSSSocketFactory init - password reader initialized\n");
- }
- } catch (Exception e) {
- debugWrite("JSSSocketFactory init - Exception caught: "
- + e.toString() + "\n");
- if (debugFile != null)
- debugFile.close();
- throw new IOException(
- "JSSSocketFactory: no passwordFilePath defined");
- }
+ String getEndpointAttribute(String tag, String defaultValue) {
+ String value = getEndpointAttribute(tag);
+ if (value == null) {
+ return defaultValue;
+ }
+ return value;
+ }
- String certDir = (String) endpoint.getAttribute("certdbDir");
+ void init() throws IOException {
+ // debug enabled?
+ String deb = getEndpointAttribute("debug");
+ if (StringUtils.equals(deb, "true")) {
+ debug = true;
+ debugFile = new FileWriter("/tmp/tomcatjss.log", true);
+ debugWrite("JSSSocketFactory init - debug is on\n");
+ }
- CryptoManager.InitializationValues vals = new CryptoManager.InitializationValues(
- certDir, "", "", "secmod.db");
+ try {
+ initializePasswordStore();
- vals.removeSunProvider = false;
- vals.installJSSProvider = true;
- try {
- CryptoManager.initialize(vals);
- } catch (AlreadyInitializedException ee) {
- // do nothing
- }
- CryptoManager manager = CryptoManager.getInstance();
+ CryptoManager manager = getCryptoManager();
// JSSSocketFactory init - handle crypto tokens
debugWrite("JSSSocketFactory init - about to handle crypto unit logins\n");
- if (mPasswordStore != null) {
- Enumeration<?> en = mPasswordStore.getTags();
- while (en.hasMoreElements()) {
- String pwd = "";
- Password pw = null;
- String tokenName = "";
- String st = (String) en.nextElement();
- debugWrite("JSSSocketFactory init - tag name=" + st + "\n");
- pwd = mPasswordStore.getPassword(st);
+ //log into tokens
+ Enumeration<String> tags = mPasswordStore.getTags();
+ while (tags.hasMoreElements()) {
+ String tag = tags.nextElement();
+ if (tag.equals("internal") || (tag.startsWith("hardware-"))) {
+ debugWrite("JSSSocketFactory init - tag name=" + tag + "\n");
+ logIntoToken(manager, tag);
+ }
+ }
+ debugWrite("JSSSocketFactory init - tokens initialized/logged in\n");
- if (pwd != null) {
- debugWrite("JSSSocketFactory init - got password\n");
- pw = new Password(pwd.toCharArray());
- } else {
- debugWrite("JSSSocketFactory init - no pwd found in password.conf\n");
- continue;
- }
-
- CryptoToken token = null;
- if (st.equals("internal")) {
- debugWrite("JSSSocketFactory init - got internal software token\n");
- token = manager.getInternalKeyStorageToken();
- } else if (st.startsWith("hardware-")) {
- debugWrite("JSSSocketFactory init - got hardware\n");
-
- tokenName = st.substring(9);
- debugWrite("JSSSocketFactory init - tokenName="
- + tokenName + "\n");
-
- // find the hsm and log in
- token = manager.getTokenByName(tokenName);
- } else {
- // non-token entries
- }
- if (token != null) {
- if (!token.isLoggedIn()) {
- debugWrite("JSSSocketFactory init -not logged in...about to log in\n");
- token.login(pw);
- } else {
- debugWrite("JSSSocketFactory init - already logged in\n");
- }
- }
- } // while
- debugWrite("JSSSocketFactory init - tokens initialized/logged in\n");
- } else {
- debugWrite("JSSSocketFactory init - no login done\n");
- } // mPasswordStore not null
-
// MUST look for "clientauth" (ALL lowercase) since "clientAuth"
// (camel case) has already been processed by Tomcat 7
- String clientAuthStr = (String) endpoint.getAttribute("clientauth");
+ String clientAuthStr = getEndpointAttribute("clientauth");
if (clientAuthStr == null) {
debugWrite("JSSSocketFactory init - \"clientauth\" not found, default to want.");
clientAuthStr = "want";
@@ -621,8 +583,10 @@
}
File file = null;
try {
- mServerCertNickPath = (String) endpoint
- .getAttribute("serverCertNickFile");
+ mServerCertNickPath = getEndpointAttribute("serverCertNickFile");
+ if (mServerCertNickPath == null) {
+ throw new IOException("serverCertNickFile not specified");
+ }
debugWrite("JSSSocketFactory init - got serverCertNickFile"
+ mServerCertNickPath + "\n");
file = new File(mServerCertNickPath);
@@ -651,13 +615,11 @@
} catch (Exception e) {
debugWrite("JSSSocketFactory init - Exception caught: "
+ e.toString() + "\n");
- if (debugFile != null)
- debugFile.close();
throw new IOException(
"JSSSocketFactory: no serverCertNickFile defined");
}
- // serverCertNick = (String)endpoint.getAttribute("serverCert");
+ // serverCertNick = (String)getEndpointAttribute("serverCert");
if (clientAuthStr.equalsIgnoreCase("true")
|| clientAuthStr.equalsIgnoreCase("yes")) {
requireClientAuth = true;
@@ -671,10 +633,9 @@
&& ocspConfigured == false) {
debugWrite("JSSSocketFactory init - checking for OCSP settings. \n");
boolean enableOCSP = false;
- String doOCSP = (String) endpoint.getAttribute("enableOCSP");
+ String doOCSP = getEndpointAttribute("enableOCSP");
- debugWrite("JSSSocketFactory init - doOCSP flag:" + doOCSP
- + " \n");
+ debugWrite("JSSSocketFactory init - doOCSP flag:" + doOCSP + " \n");
if (doOCSP != null && doOCSP.equalsIgnoreCase("true")) {
enableOCSP = true;
@@ -684,17 +645,15 @@
+ "\n");
if (enableOCSP == true) {
- String ocspResponderURL = (String) endpoint
- .getAttribute("ocspResponderURL");
+ String ocspResponderURL = getEndpointAttribute("ocspResponderURL");
debugWrite("JSSSocketFactory init - ocspResponderURL "
+ ocspResponderURL + "\n");
- String ocspResponderCertNickname = (String) endpoint
- .getAttribute("ocspResponderCertNickname");
+ String ocspResponderCertNickname = getEndpointAttribute(
+ "ocspResponderCertNickname");
debugWrite("JSSSocketFactory init - ocspResponderCertNickname"
+ ocspResponderCertNickname + "\n");
- if ((ocspResponderURL != null && ocspResponderURL.length() > 0)
- && (ocspResponderCertNickname != null && ocspResponderCertNickname
- .length() > 0)) {
+ if (StringUtils.isNotEmpty(ocspResponderURL) &&
+ StringUtils.isNotEmpty(ocspResponderCertNickname)) {
ocspConfigured = true;
try {
@@ -704,12 +663,9 @@
int ocspMinCacheEntryDuration_i = 3600;
int ocspMaxCacheEntryDuration_i = 86400;
- String ocspCacheSize = (String) endpoint
- .getAttribute("ocspCacheSize");
- String ocspMinCacheEntryDuration = (String) endpoint
- .getAttribute("ocspMinCacheEntryDuration");
- String ocspMaxCacheEntryDuration = (String) endpoint
- .getAttribute("ocspMaxCacheEntryDuration");
+ String ocspCacheSize = getEndpointAttribute("ocspCacheSize");
+ String ocspMinCacheEntryDuration = getEndpointAttribute("ocspMinCacheEntryDuration");
+ String ocspMaxCacheEntryDuration = getEndpointAttribute("ocspMaxCacheEntryDuration");
if (ocspCacheSize != null
|| ocspMinCacheEntryDuration != null
@@ -718,20 +674,17 @@
if (ocspCacheSize != null) {
debugWrite("JSSSocketFactory init - ocspCacheSize= "
+ ocspCacheSize + "\n");
- ocspCacheSize_i = Integer
- .parseInt(ocspCacheSize);
+ ocspCacheSize_i = Integer.parseInt(ocspCacheSize);
}
if (ocspMinCacheEntryDuration != null) {
debugWrite("JSSSocketFactory init - ocspMinCacheEntryDuration= "
+ ocspMinCacheEntryDuration + "\n");
- ocspMinCacheEntryDuration_i = Integer
- .parseInt(ocspMinCacheEntryDuration);
+ ocspMinCacheEntryDuration_i = Integer.parseInt(ocspMinCacheEntryDuration);
}
if (ocspMaxCacheEntryDuration != null) {
debugWrite("JSSSocketFactory init - ocspMaxCacheEntryDuration= "
+ ocspMaxCacheEntryDuration + "\n");
- ocspMaxCacheEntryDuration_i = Integer
- .parseInt(ocspMaxCacheEntryDuration);
+ ocspMaxCacheEntryDuration_i = Integer.parseInt(ocspMaxCacheEntryDuration);
}
manager.OCSPCacheSettings(ocspCacheSize_i,
ocspMinCacheEntryDuration_i,
@@ -739,18 +692,14 @@
}
// defualt to 60 seconds;
- String ocspTimeout = (String) endpoint
- .getAttribute("ocspTimeout");
+ String ocspTimeout = getEndpointAttribute("ocspTimeout");
if (ocspTimeout != null) {
- debugWrite("JSSSocketFactory init - ocspTimeout= \n"
- + ocspTimeout);
- int ocspTimeout_i = Integer
- .parseInt(ocspTimeout);
+ debugWrite("JSSSocketFactory init - ocspTimeout= \n" + ocspTimeout);
+ int ocspTimeout_i = Integer.parseInt(ocspTimeout);
if (ocspTimeout_i < 0)
ocspTimeout_i = 60;
manager.setOCSPTimeout(ocspTimeout_i);
}
-
} catch (java.security.GeneralSecurityException e) {
ocspConfigured = false;
debugWrite("JSSSocketFactory init - error initializing OCSP e: "
@@ -774,10 +723,9 @@
// 12 hours = 43200 seconds
SSLServerSocket.configServerSessionIDCache(0, 43200, 43200, null);
- String strictCiphersStr = (String) endpoint
- .getAttribute("strictCiphers");
- if (strictCiphersStr.equalsIgnoreCase("true")
- || strictCiphersStr.equalsIgnoreCase("yes")) {
+ String strictCiphersStr = getEndpointAttribute("strictCiphers");
+ if (StringUtils.equalsIgnoreCase(strictCiphersStr, "true")
+ || StringUtils.equalsIgnoreCase(strictCiphersStr, "yes")) {
mStrictCiphers = true;
}
if (mStrictCiphers == true) {
@@ -788,8 +736,7 @@
debugWrite("SSSocketFactory init - before setSSLCiphers, strictCiphers is false\n");
}
- String sslVersionRangeStream = (String) endpoint
- .getAttribute("sslVersionRangeStream");
+ String sslVersionRangeStream = getEndpointAttribute("sslVersionRangeStream");
if ((sslVersionRangeStream != null)
&& !sslVersionRangeStream.equals("")) {
debugWrite("SSSocketFactory init - calling setSSLVersionRangeDefault() for type STREAM\n");
@@ -799,8 +746,7 @@
debugWrite("SSSocketFactory init - after setSSLVersionRangeDefault() for type STREAM\n");
}
- String sslVersionRangeDatagram = (String) endpoint
- .getAttribute("sslVersionRangeDatagram");
+ String sslVersionRangeDatagram = getEndpointAttribute("sslVersionRangeDatagram");
if ((sslVersionRangeDatagram != null)
&& !sslVersionRangeDatagram.equals("")) {
debugWrite("SSSocketFactory init - calling setSSLVersionRangeDefault() for type DATA_GRAM\n");
@@ -838,8 +784,6 @@
+ ex.toString() + "\n");
System.err.println("JSSSocketFactory init - exception thrown:"
+ ex.toString() + "\n");
- if (debugFile != null)
- debugFile.close();
// The idea is, if admin take the trouble to configure the
// ocsp cache, and made a mistake, we want to make server
// unavailable until they get it right
@@ -846,11 +790,109 @@
if ((ex instanceof java.security.GeneralSecurityException)
|| (ex instanceof java.lang.NumberFormatException))
throw new IOException(ex.toString());
+ } finally {
+ if (debugFile != null)
+ debugFile.close();
}
- if (debugFile != null)
- debugFile.close();
}
+ private CryptoToken getToken(String tag, CryptoManager manager) throws IOException, NoSuchTokenException {
+ CryptoToken token = null;
+ if (tag.equals("internal")) {
+ debugWrite("JSSSocketFactory init - got internal software token\n");
+ token = manager.getInternalKeyStorageToken();
+ } else if (tag.startsWith("hardware-")) {
+ debugWrite("JSSSocketFactory init - got hardware\n");
+
+ String tokenName = tag.substring(9);
+ debugWrite("JSSSocketFactory init - tokenName=" + tokenName + "\n");
+
+ // find the hsm and log in
+ token = manager.getTokenByName(tokenName);
+ } else {
+ // non-token password entry
+ }
+ return token;
+ }
+
+ private void initializePasswordStore() throws InstantiationException, IllegalAccessException,
+ ClassNotFoundException, IOException {
+ mPwdClass = getEndpointAttribute("passwordClass");
+ if (mPwdClass == null) {
+ throw new IOException("Misconfiguration: passwordClass is not defined");
+ }
+ mPwdPath = getEndpointAttribute("passwordFile");
+
+ mPasswordStore = (IPasswordStore) Class.forName(mPwdClass).newInstance();
+ debugWrite("JSSSocketFactory init - password reader initialized\n");
+
+ // initialize the password store
+ mPasswordStore.init(mPwdPath);
+ }
+
+ private CryptoManager getCryptoManager() throws KeyDatabaseException, CertDatabaseException,
+ GeneralSecurityException, NotInitializedException, IOException {
+ String certDir = getEndpointAttribute("certdbDir");
+ if (certDir == null) {
+ throw new IOException("Misconfiguration: certdir not defined");
+ }
+ CryptoManager.InitializationValues vals = new CryptoManager.InitializationValues(
+ certDir, "", "", "secmod.db");
+
+ vals.removeSunProvider = false;
+ vals.installJSSProvider = true;
+ try {
+ CryptoManager.initialize(vals);
+ } catch (AlreadyInitializedException ee) {
+ // do nothing
+ }
+ CryptoManager manager = CryptoManager.getInstance();
+ return manager;
+ }
+
+ private void logIntoToken(CryptoManager manager, String tag) throws IOException,
+ TokenException {
+ String pwd;
+ Password pw = null;
+ int iteration = 0;
+
+ CryptoToken token = null;
+ try {
+ token = getToken(tag, manager);
+ } catch (NoSuchTokenException e) {
+ debugWrite("token for " + tag + " not found by CryptoManager. Not logging in.");
+ return;
+ }
+
+ do {
+ debugWrite("JSSSocketFactory init - iteration=" + iteration + "\n");
+ pwd = mPasswordStore.getPassword(tag, iteration);
+ if (pwd == null) {
+ debugWrite("JSSSocketFactory init - no pwd gotten\n");
+ return;
+ }
+
+ pw = new Password(pwd.toCharArray());
+
+ if (!token.isLoggedIn()) {
+ debugWrite("JSSSocketFactory init -not logged in...about to log in\n");
+ try {
+ token.login(pw);
+ break;
+ } catch (IncorrectPasswordException e) {
+ debugWrite("Incorrect password received");
+ iteration ++;
+ if (iteration == MAX_PW_ATTEMPTS) {
+ debugWrite("Failed to log into token:" + tag);
+ }
+ }
+ } else {
+ debugWrite("JSSSocketFactory init - already logged in\n");
+ break;
+ }
+ } while (iteration < MAX_PW_ATTEMPTS);
+ }
+
public Socket acceptSocket(ServerSocket socket) throws IOException {
SSLSocket asock = null;
try {
@@ -892,10 +934,9 @@
if (!initialized)
init();
SSLServerSocket socket = null;
- socket = (SSLServerSocket) (new SSLServerSocket(port, backlog,
- ifAddress, null, reuseAddr));
+ socket = new SSLServerSocket(port, backlog, ifAddress, null, reuseAddr);
initializeSocket(socket);
- return (ServerSocket) socket;
+ return socket;
}
private void initializeSocket(SSLServerSocket s) {
Index: src/org/apache/tomcat/util/net/jss/PlainPasswordFile.java
===================================================================
--- src/org/apache/tomcat/util/net/jss/PlainPasswordFile.java (revision 294)
+++ src/org/apache/tomcat/util/net/jss/PlainPasswordFile.java (revision 297)
@@ -12,7 +12,7 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
+ *
* Copyright (C) 2007 Red Hat, Inc.
* All rights reserved.
* END COPYRIGHT BLOCK */
@@ -43,9 +43,13 @@
}
public String getPassword(String tag) {
- return (String) mPwdStore.getProperty(tag);
+ return getPassword(tag, 0);
}
+ public String getPassword(String tag, int iteration) {
+ return mPwdStore.getProperty(tag);
+ }
+
// return an array of String-based tag
@SuppressWarnings("unchecked")
public Enumeration<String> getTags() {
Index: src/org/apache/tomcat/util/net/jss/IPasswordStore.java
===================================================================
--- src/org/apache/tomcat/util/net/jss/IPasswordStore.java (revision 294)
+++ src/org/apache/tomcat/util/net/jss/IPasswordStore.java (revision 297)
@@ -12,7 +12,7 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
+ *
* Copyright (C) 2007 Red Hat, Inc.
* All rights reserved.
* END COPYRIGHT BLOCK */
@@ -25,6 +25,8 @@
public interface IPasswordStore {
public void init(String pwdPath) throws IOException;
+ public String getPassword(String tag, int iteration);
+
public String getPassword(String tag);
public Enumeration<String> getTags();
Index: build.xml
===================================================================
--- build.xml (revision 294)
+++ build.xml (revision 297)
@@ -104,6 +104,7 @@
<!-- This property is set to '/dirsec' when built on rhel4 -->
<property name="dirsec" value="" />
<property name="jss.jar" value="${jss.home}${dirsec}/jss4.jar" />
+ <property name="commons-lang.jar" value="${jar.home}/commons-lang.jar" />
<!--
Classpath
@@ -112,6 +113,7 @@
<pathelement location="${jss.jar}"/>
<pathelement location="${tomcat-coyote.jar}"/>
<pathelement location="${commons-logging.jar}"/>
+ <pathelement location="${commons-lang.jar}"/>
</path>
<!--