Return-Path:
URL is designed to provide public APIs for parsing
+ * and synthesizing Uniform Resource Locators as similar as possible to the
+ * APIs of WARNING - This class assumes that the string
+ * representation of a URL conforms to the java.net.URL
, but without the ability to open a
+ * stream or connection. One of the consequences of this is that you can
+ * construct URLs for protocols for which a URLStreamHandler is not
+ * available (such as an "https" URL when JSSE is not installed).spec
argument
+ * as described in RFC 2396 "Uniform Resource Identifiers: Generic Syntax":
+ *
+ * <scheme>//<authority><path>?<query>#<fragment>
+ *
FIXME - This class really ought to end up in a Commons + * package someplace.
+ * + * @author Craig R. McClanahan + * @version $Id: URL.java 939351 2010-04-29 15:41:54Z kkolinko $ + */ + +public final class URL implements Serializable { + + + // ----------------------------------------------------------- Constructors + + + /** + * Create a URL object from the specified String representation. + * + * @param spec String representation of the URL + * + * @exception MalformedURLException if the string representation + * cannot be parsed successfully + */ + public URL(String spec) throws MalformedURLException { + + this(null, spec); + + } + + + /** + * Create a URL object by parsing a string representation relative + * to a specified context. Based on logic from JDK 1.3.1's + *java.net.URL
.
+ *
+ * @param context URL against which the relative representation
+ * is resolved
+ * @param spec String representation of the URL (usually relative)
+ *
+ * @exception MalformedURLException if the string representation
+ * cannot be parsed successfully
+ */
+ public URL(URL context, String spec) throws MalformedURLException {
+
+ String original = spec;
+ int i, limit, c;
+ int start = 0;
+ String newProtocol = null;
+ boolean aRef = false;
+
+ try {
+
+ // Eliminate leading and trailing whitespace
+ limit = spec.length();
+ while ((limit > 0) && (spec.charAt(limit - 1) <= ' ')) {
+ limit--;
+ }
+ while ((start < limit) && (spec.charAt(start) <= ' ')) {
+ start++;
+ }
+
+ // If the string representation starts with "url:", skip it
+ if (spec.regionMatches(true, start, "url:", 0, 4)) {
+ start += 4;
+ }
+
+ // Is this a ref relative to the context URL?
+ if ((start < spec.length()) && (spec.charAt(start) == '#')) {
+ aRef = true;
+ }
+
+ // Parse out the new protocol
+ for (i = start; !aRef && (i < limit) ; i++) {
+ c = spec.charAt(i);
+ if (c == ':') {
+ String s = spec.substring(start, i).toLowerCase();
+ // Assume all protocols are valid
+ newProtocol = s;
+ start = i + 1;
+ break;
+ } else if( c == '#' ) {
+ aRef = true;
+ } else if( !isSchemeChar((char)c) ) {
+ break;
+ }
+ }
+
+ // Only use our context if the protocols match
+ protocol = newProtocol;
+ if ((context != null) && ((newProtocol == null) ||
+ newProtocol.equalsIgnoreCase(context.getProtocol()))) {
+ // If the context is a hierarchical URL scheme and the spec
+ // contains a matching scheme then maintain backwards
+ // compatibility and treat it as if the spec didn't contain
+ // the scheme; see 5.2.3 of RFC2396
+ if ((context.getPath() != null) &&
+ (context.getPath().startsWith("/")))
+ newProtocol = null;
+ if (newProtocol == null) {
+ protocol = context.getProtocol();
+ authority = context.getAuthority();
+ userInfo = context.getUserInfo();
+ host = context.getHost();
+ port = context.getPort();
+ file = context.getFile();
+ int question = file.lastIndexOf("?");
+ if (question < 0)
+ path = file;
+ else
+ path = file.substring(0, question);
+ }
+ }
+
+ if (protocol == null)
+ throw new MalformedURLException("no protocol: " + original);
+
+ // Parse out any ref portion of the spec
+ i = spec.indexOf('#', start);
+ if (i >= 0) {
+ ref = spec.substring(i + 1, limit);
+ limit = i;
+ }
+
+ // Parse the remainder of the spec in a protocol-specific fashion
+ parse(spec, start, limit);
+ if (context != null)
+ normalize();
+
+
+ } catch (MalformedURLException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new MalformedURLException(e.toString());
+ }
+
+ }
+
+
+
+
+
+ /**
+ * Create a URL object from the specified components. The default port
+ * number for the specified protocol will be used.
+ *
+ * @param protocol Name of the protocol to use
+ * @param host Name of the host addressed by this protocol
+ * @param file Filename on the specified host
+ *
+ * @exception MalformedURLException is never thrown, but present for
+ * compatible APIs
+ */
+ public URL(String protocol, String host, String file)
+ throws MalformedURLException {
+
+ this(protocol, host, -1, file);
+
+ }
+
+
+ /**
+ * Create a URL object from the specified components. Specifying a port
+ * number of -1 indicates that the URL should use the default port for
+ * that protocol. Based on logic from JDK 1.3.1's
+ * java.net.URL
.
+ *
+ * @param protocol Name of the protocol to use
+ * @param host Name of the host addressed by this protocol
+ * @param port Port number, or -1 for the default port for this protocol
+ * @param file Filename on the specified host
+ *
+ * @exception MalformedURLException is never thrown, but present for
+ * compatible APIs
+ */
+ public URL(String protocol, String host, int port, String file)
+ throws MalformedURLException {
+
+ this.protocol = protocol;
+ this.host = host;
+ this.port = port;
+
+ int hash = file.indexOf('#');
+ this.file = hash < 0 ? file : file.substring(0, hash);
+ this.ref = hash < 0 ? null : file.substring(hash + 1);
+ int question = file.lastIndexOf('?');
+ if (question >= 0) {
+ query = file.substring(question + 1);
+ path = file.substring(0, question);
+ } else
+ path = file;
+
+ if ((host != null) && (host.length() > 0))
+ authority = (port == -1) ? host : host + ":" + port;
+
+ }
+
+
+ // ----------------------------------------------------- Instance Variables
+
+
+ /**
+ * The authority part of the URL.
+ */
+ private String authority = null;
+
+
+ /**
+ * The filename part of the URL.
+ */
+ private String file = null;
+
+
+ /**
+ * The host name part of the URL.
+ */
+ private String host = null;
+
+
+ /**
+ * The path part of the URL.
+ */
+ private String path = null;
+
+
+ /**
+ * The port number part of the URL.
+ */
+ private int port = -1;
+
+
+ /**
+ * The protocol name part of the URL.
+ */
+ private String protocol = null;
+
+
+ /**
+ * The query part of the URL.
+ */
+ private String query = null;
+
+
+ /**
+ * The reference part of the URL.
+ */
+ private String ref = null;
+
+
+ /**
+ * The user info part of the URL.
+ */
+ private String userInfo = null;
+
+
+ // --------------------------------------------------------- Public Methods
+
+
+ /**
+ * Compare two URLs for equality. The result is true
if and
+ * only if the argument is not null, and is a URL
object
+ * that represents the same URL
as this object. Two
+ * URLs
are equal if they have the same protocol and
+ * reference the same host, the same port number on the host,
+ * and the same file and anchor on the host.
+ *
+ * @param obj The URL to compare against
+ */
+ public boolean equals(Object obj) {
+
+ if (obj == null)
+ return (false);
+ if (!(obj instanceof URL))
+ return (false);
+ URL other = (URL) obj;
+ if (!sameFile(other))
+ return (false);
+ return (compare(ref, other.getRef()));
+
+ }
+
+
+ /**
+ * Return the authority part of the URL.
+ */
+ public String getAuthority() {
+
+ return (this.authority);
+
+ }
+
+
+ /**
+ * Return the filename part of the URL. NOTE - For
+ * compatibility with java.net.URL
, this value includes
+ * the query string if there was one. For just the path portion,
+ * call getPath()
instead.
+ */
+ public String getFile() {
+
+ if (file == null)
+ return ("");
+ return (this.file);
+
+ }
+
+
+ /**
+ * Return the host name part of the URL.
+ */
+ public String getHost() {
+
+ return (this.host);
+
+ }
+
+
+ /**
+ * Return the path part of the URL.
+ */
+ public String getPath() {
+
+ if (this.path == null)
+ return ("");
+ return (this.path);
+
+ }
+
+
+ /**
+ * Return the port number part of the URL.
+ */
+ public int getPort() {
+
+ return (this.port);
+
+ }
+
+
+ /**
+ * Return the protocol name part of the URL.
+ */
+ public String getProtocol() {
+
+ return (this.protocol);
+
+ }
+
+
+ /**
+ * Return the query part of the URL.
+ */
+ public String getQuery() {
+
+ return (this.query);
+
+ }
+
+
+ /**
+ * Return the reference part of the URL.
+ */
+ public String getRef() {
+
+ return (this.ref);
+
+ }
+
+
+ /**
+ * Return the user info part of the URL.
+ */
+ public String getUserInfo() {
+
+ return (this.userInfo);
+
+ }
+
+
+ /**
+ * Normalize the path
(and therefore file
)
+ * portions of this URL.
+ *
+ * NOTE - This method is not part of the public API
+ * of java.net.URL
, but is provided as a value added
+ * service of this implementation.
+ *
+ * @exception MalformedURLException if a normalization error occurs,
+ * such as trying to move about the hierarchical root
+ */
+ public void normalize() throws MalformedURLException {
+
+ // Special case for null path
+ if (path == null) {
+ if (query != null)
+ file = "?" + query;
+ else
+ file = "";
+ return;
+ }
+
+ // Create a place for the normalized path
+ String normalized = path;
+ if (normalized.equals("/.")) {
+ path = "/";
+ if (query != null)
+ file = path + "?" + query;
+ else
+ file = path;
+ return;
+ }
+
+ // Normalize the slashes and add leading slash if necessary
+ if (normalized.indexOf('\\') >= 0)
+ normalized = normalized.replace('\\', '/');
+ if (!normalized.startsWith("/"))
+ normalized = "/" + normalized;
+
+ // Resolve occurrences of "//" in the normalized path
+ while (true) {
+ int index = normalized.indexOf("//");
+ if (index < 0)
+ break;
+ normalized = normalized.substring(0, index) +
+ normalized.substring(index + 1);
+ }
+
+ // Resolve occurrences of "/./" in the normalized path
+ while (true) {
+ int index = normalized.indexOf("/./");
+ if (index < 0)
+ break;
+ normalized = normalized.substring(0, index) +
+ normalized.substring(index + 2);
+ }
+
+ // Resolve occurrences of "/../" in the normalized path
+ while (true) {
+ int index = normalized.indexOf("/../");
+ if (index < 0)
+ break;
+ if (index == 0)
+ throw new MalformedURLException
+ ("Invalid relative URL reference");
+ int index2 = normalized.lastIndexOf('/', index - 1);
+ normalized = normalized.substring(0, index2) +
+ normalized.substring(index + 3);
+ }
+
+ // Resolve occurrences of "/." at the end of the normalized path
+ if (normalized.endsWith("/."))
+ normalized = normalized.substring(0, normalized.length() - 1);
+
+ // Resolve occurrences of "/.." at the end of the normalized path
+ if (normalized.endsWith("/..")) {
+ int index = normalized.length() - 3;
+ int index2 = normalized.lastIndexOf('/', index - 1);
+ if (index2 < 0)
+ throw new MalformedURLException
+ ("Invalid relative URL reference");
+ normalized = normalized.substring(0, index2 + 1);
+ }
+
+ // Return the normalized path that we have completed
+ path = normalized;
+ if (query != null)
+ file = path + "?" + query;
+ else
+ file = path;
+
+ }
+
+
+ /**
+ * Compare two URLs, excluding the "ref" fields. Returns true
+ * if this URL
and the other
argument both refer
+ * to the same resource. The two URLs
might not both contain
+ * the same anchor.
+ */
+ public boolean sameFile(URL other) {
+
+ if (!compare(protocol, other.getProtocol()))
+ return (false);
+ if (!compare(host, other.getHost()))
+ return (false);
+ if (port != other.getPort())
+ return (false);
+ if (!compare(file, other.getFile()))
+ return (false);
+ return (true);
+
+ }
+
+
+ /**
+ * Return a string representation of this URL. This follow the rules in
+ * RFC 2396, Section 5.2, Step 7.
+ */
+ public String toExternalForm() {
+
+ StringBuffer sb = new StringBuffer();
+ if (protocol != null) {
+ sb.append(protocol);
+ sb.append(":");
+ }
+ if (authority != null) {
+ sb.append("//");
+ sb.append(authority);
+ }
+ if (path != null)
+ sb.append(path);
+ if (query != null) {
+ sb.append('?');
+ sb.append(query);
+ }
+ if (ref != null) {
+ sb.append('#');
+ sb.append(ref);
+ }
+ return (sb.toString());
+
+ }
+
+
+ /**
+ * Return a string representation of this object.
+ */
+ public String toString() {
+
+ StringBuffer sb = new StringBuffer("URL[");
+ sb.append("authority=");
+ sb.append(authority);
+ sb.append(", file=");
+ sb.append(file);
+ sb.append(", host=");
+ sb.append(host);
+ sb.append(", port=");
+ sb.append(port);
+ sb.append(", protocol=");
+ sb.append(protocol);
+ sb.append(", query=");
+ sb.append(query);
+ sb.append(", ref=");
+ sb.append(ref);
+ sb.append(", userInfo=");
+ sb.append(userInfo);
+ sb.append("]");
+ return (sb.toString());
+
+ // return (toExternalForm());
+
+ }
+
+
+ // -------------------------------------------------------- Private Methods
+
+
+ /**
+ * Compare to String values for equality, taking appropriate care if one
+ * or both of the values are null
.
+ *
+ * @param first First string
+ * @param second Second string
+ */
+ private boolean compare(String first, String second) {
+
+ if (first == null) {
+ if (second == null)
+ return (true);
+ else
+ return (false);
+ } else {
+ if (second == null)
+ return (false);
+ else
+ return (first.equals(second));
+ }
+
+ }
+
+
+ /**
+ * Parse the specified portion of the string representation of a URL,
+ * assuming that it has a format similar to that for http
.
+ *
+ *
FIXME - This algorithm can undoubtedly be optimized + * for performance. However, that needs to wait until after sufficient + * unit tests are implemented to guarantee correct behavior with no + * regressions.
+ * + * @param spec String representation being parsed + * @param start Starting offset, which will be just after the ':' (if + * there is one) that determined the protocol name + * @param limit Ending position, which will be the position of the '#' + * (if there is one) that delimited the anchor + * + * @exception MalformedURLException if a parsing error occurs + */ + private void parse(String spec, int start, int limit) + throws MalformedURLException { + + // Trim the query string (if any) off the tail end + int question = spec.lastIndexOf('?', limit - 1); + if ((question >= 0) && (question < limit)) { + query = spec.substring(question + 1, limit); + limit = question; + } else { + query = null; + } + + // Parse the authority section + if (spec.indexOf("//", start) == start) { + int pathStart = spec.indexOf("/", start + 2); + if ((pathStart >= 0) && (pathStart < limit)) { + authority = spec.substring(start + 2, pathStart); + start = pathStart; + } else { + authority = spec.substring(start + 2, limit); + start = limit; + } + if (authority.length() > 0) { + int at = authority.indexOf('@'); + if( at >= 0 ) { + userInfo = authority.substring(0,at); + } + int ipv6 = authority.indexOf('[',at+1); + int hStart = at+1; + if( ipv6 >= 0 ) { + hStart = ipv6; + ipv6 = authority.indexOf(']', ipv6); + if( ipv6 < 0 ) { + throw new MalformedURLException( + "Closing ']' not found in IPV6 address: " + authority); + } else { + at = ipv6-1; + } + } + + int colon = authority.indexOf(':', at+1); + if (colon >= 0) { + try { + port = + Integer.parseInt(authority.substring(colon + 1)); + } catch (NumberFormatException e) { + throw new MalformedURLException(e.toString()); + } + host = authority.substring(hStart, colon); + } else { + host = authority.substring(hStart); + port = -1; + } + } + } + + // Parse the path section + if (spec.indexOf("/", start) == start) { // Absolute path + path = spec.substring(start, limit); + if (query != null) + file = path + "?" + query; + else + file = path; + return; + } + + // Resolve relative path against our context's file + if (path == null) { + if (query != null) + file = "?" + query; + else + file = null; + return; + } + if (!path.startsWith("/")) + throw new MalformedURLException + ("Base path does not start with '/'"); + if (!path.endsWith("/")) + path += "/../"; + path += spec.substring(start, limit); + if (query != null) + file = path + "?" + query; + else + file = path; + return; + + } + + /** + * Determine if the character is allowed in the scheme of a URI. + * See RFC 2396, Section 3.1 + */ + public static boolean isSchemeChar(char c) { + return Character.isLetterOrDigit(c) || + c == '+' || c == '-' || c == '.'; + } + +} Added: geronimo/external/trunk/tomcat-parent-6.0.35/catalina/src/main/java/org/apache/tomcat/util/net/jsse/JSSEFactory.java URL: http://svn.apache.org/viewvc/geronimo/external/trunk/tomcat-parent-6.0.35/catalina/src/main/java/org/apache/tomcat/util/net/jsse/JSSEFactory.java?rev=1214761&view=auto ============================================================================== --- geronimo/external/trunk/tomcat-parent-6.0.35/catalina/src/main/java/org/apache/tomcat/util/net/jsse/JSSEFactory.java (added) +++ geronimo/external/trunk/tomcat-parent-6.0.35/catalina/src/main/java/org/apache/tomcat/util/net/jsse/JSSEFactory.java Thu Dec 15 13:55:25 2011 @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.net.jsse; + +import java.net.Socket; + +import javax.net.ssl.SSLSocket; + +import org.apache.tomcat.util.net.SSLSupport; +import org.apache.tomcat.util.net.ServerSocketFactory; +import javax.net.ssl.SSLSession; + +/** + * Factory interface to construct components based on the JSSE version + * in use. + * + * @author Bill Barker + * @author Filip Hanik + */ + +public class JSSEFactory { + + /** + * Returns the ServerSocketFactory to use. + */ + public ServerSocketFactory getSocketFactory() { + return new JSSESocketFactory(); + } + + /** + * returns the SSLSupport attached to this socket. + */ + public SSLSupport getSSLSupport(Socket socket) { + return new JSSESupport((SSLSocket)socket); + } + + public SSLSupport getSSLSupport(SSLSession session) { + return new JSSESupport(session); + } + +}; Added: geronimo/external/trunk/tomcat-parent-6.0.35/catalina/src/main/java/org/apache/tomcat/util/net/jsse/JSSEImplementation.java URL: http://svn.apache.org/viewvc/geronimo/external/trunk/tomcat-parent-6.0.35/catalina/src/main/java/org/apache/tomcat/util/net/jsse/JSSEImplementation.java?rev=1214761&view=auto ============================================================================== --- geronimo/external/trunk/tomcat-parent-6.0.35/catalina/src/main/java/org/apache/tomcat/util/net/jsse/JSSEImplementation.java (added) +++ geronimo/external/trunk/tomcat-parent-6.0.35/catalina/src/main/java/org/apache/tomcat/util/net/jsse/JSSEImplementation.java Thu Dec 15 13:55:25 2011 @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.net.jsse; + +import java.net.Socket; + +import org.apache.tomcat.util.net.SSLImplementation; +import org.apache.tomcat.util.net.SSLSupport; +import org.apache.tomcat.util.net.ServerSocketFactory; +import javax.net.ssl.SSLSession; + +/* JSSEImplementation: + + Concrete implementation class for JSSE + + @author EKR +*/ + +public class JSSEImplementation extends SSLImplementation +{ + static final String SSLSocketClass = "javax.net.ssl.SSLSocket"; + + static org.apache.juli.logging.Log logger = + org.apache.juli.logging.LogFactory.getLog(JSSEImplementation.class); + + private JSSEFactory factory = null; + + public JSSEImplementation() throws ClassNotFoundException { + // Check to see if JSSE is floating around somewhere + Class.forName(SSLSocketClass); + factory = new JSSEFactory(); + } + + + public String getImplementationName(){ + return "JSSE"; + } + + public ServerSocketFactory getServerSocketFactory() { + ServerSocketFactory ssf = factory.getSocketFactory(); + return ssf; + } + + public SSLSupport getSSLSupport(Socket s) { + SSLSupport ssls = factory.getSSLSupport(s); + return ssls; + } + + public SSLSupport getSSLSupport(SSLSession session) { + SSLSupport ssls = factory.getSSLSupport(session); + return ssls; + } + +} Added: geronimo/external/trunk/tomcat-parent-6.0.35/catalina/src/main/java/org/apache/tomcat/util/net/jsse/JSSEKeyManager.java URL: http://svn.apache.org/viewvc/geronimo/external/trunk/tomcat-parent-6.0.35/catalina/src/main/java/org/apache/tomcat/util/net/jsse/JSSEKeyManager.java?rev=1214761&view=auto ============================================================================== --- geronimo/external/trunk/tomcat-parent-6.0.35/catalina/src/main/java/org/apache/tomcat/util/net/jsse/JSSEKeyManager.java (added) +++ geronimo/external/trunk/tomcat-parent-6.0.35/catalina/src/main/java/org/apache/tomcat/util/net/jsse/JSSEKeyManager.java Thu Dec 15 13:55:25 2011 @@ -0,0 +1,144 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.net.jsse; + +import java.net.Socket; +import java.security.Principal; +import java.security.PrivateKey; +import java.security.cert.X509Certificate; +import javax.net.ssl.X509KeyManager; + +/** + * X509KeyManager which allows selection of a specific keypair and certificate + * chain (identified by their keystore alias name) to be used by the server to + * authenticate itself to SSL clients. + * + * @author Jan Luehe + */ +public final class JSSEKeyManager implements X509KeyManager { + + private X509KeyManager delegate; + private String serverKeyAlias; + + /** + * Constructor. + * + * @param mgr The X509KeyManager used as a delegate + * @param serverKeyAlias The alias name of the server's keypair and + * supporting certificate chain + */ + public JSSEKeyManager(X509KeyManager mgr, String serverKeyAlias) { + this.delegate = mgr; + this.serverKeyAlias = serverKeyAlias; + } + + /** + * Choose an alias to authenticate the client side of a secure socket, + * given the public key type and the list of certificate issuer authorities + * recognized by the peer (if any). + * + * @param keyType The key algorithm type name(s), ordered with the + * most-preferred key type first + * @param issuers The list of acceptable CA issuer subject names, or null + * if it does not matter which issuers are used + * @param socket The socket to be used for this connection. This parameter + * can be null, in which case this method will return the most generic + * alias to use + * + * @return The alias name for the desired key, or null if there are no + * matches + */ + public String chooseClientAlias(String[] keyType, Principal[] issuers, + Socket socket) { + return delegate.chooseClientAlias(keyType, issuers, socket); + } + + /** + * Returns this key manager's server key alias that was provided in the + * constructor. + * + * @param keyType The key algorithm type name (ignored) + * @param issuers The list of acceptable CA issuer subject names, or null + * if it does not matter which issuers are used (ignored) + * @param socket The socket to be used for this connection. This parameter + * can be null, in which case this method will return the most generic + * alias to use (ignored) + * + * @return Alias name for the desired key + */ + public String chooseServerAlias(String keyType, Principal[] issuers, + Socket socket) { + return serverKeyAlias; + } + + /** + * Returns the certificate chain associated with the given alias. + * + * @param alias The alias name + * + * @return Certificate chain (ordered with the user's certificate first + * and the root certificate authority last), or null if the alias can't be + * found + */ + public X509Certificate[] getCertificateChain(String alias) { + return delegate.getCertificateChain(alias); + } + + /** + * Get the matching aliases for authenticating the client side of a secure + * socket, given the public key type and the list of certificate issuer + * authorities recognized by the peer (if any). + * + * @param keyType The key algorithm type name + * @param issuers The list of acceptable CA issuer subject names, or null + * if it does not matter which issuers are used + * + * @return Array of the matching alias names, or null if there were no + * matches + */ + public String[] getClientAliases(String keyType, Principal[] issuers) { + return delegate.getClientAliases(keyType, issuers); + } + + /** + * Get the matching aliases for authenticating the server side of a secure + * socket, given the public key type and the list of certificate issuer + * authorities recognized by the peer (if any). + * + * @param keyType The key algorithm type name + * @param issuers The list of acceptable CA issuer subject names, or null + * if it does not matter which issuers are used + * + * @return Array of the matching alias names, or null if there were no + * matches + */ + public String[] getServerAliases(String keyType, Principal[] issuers) { + return delegate.getServerAliases(keyType, issuers); + } + + /** + * Returns the key associated with the given alias. + * + * @param alias The alias name + * + * @return The requested key, or null if the alias can't be found + */ + public PrivateKey getPrivateKey(String alias) { + return delegate.getPrivateKey(alias); + } +} Added: geronimo/external/trunk/tomcat-parent-6.0.35/catalina/src/main/java/org/apache/tomcat/util/net/jsse/JSSESocketFactory.java URL: http://svn.apache.org/viewvc/geronimo/external/trunk/tomcat-parent-6.0.35/catalina/src/main/java/org/apache/tomcat/util/net/jsse/JSSESocketFactory.java?rev=1214761&view=auto ============================================================================== --- geronimo/external/trunk/tomcat-parent-6.0.35/catalina/src/main/java/org/apache/tomcat/util/net/jsse/JSSESocketFactory.java (added) +++ geronimo/external/trunk/tomcat-parent-6.0.35/catalina/src/main/java/org/apache/tomcat/util/net/jsse/JSSESocketFactory.java Thu Dec 15 13:55:25 2011 @@ -0,0 +1,869 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.net.jsse; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketException; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.cert.CRL; +import java.security.cert.CRLException; +import java.security.cert.CertPathParameters; +import java.security.cert.CertStore; +import java.security.cert.CertStoreParameters; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.CollectionCertStoreParameters; +import java.security.cert.PKIXBuilderParameters; +import java.security.cert.X509CertSelector; +import java.util.Collection; +import java.util.Vector; + +import javax.net.ssl.CertPathTrustManagerParameters; +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.ManagerFactoryParameters; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.SSLSessionContext; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509KeyManager; + +import org.apache.tomcat.util.res.StringManager; + +/* + 1. Make the JSSE's jars available, either as an installed + extension (copy them into jre/lib/ext) or by adding + them to the Tomcat classpath. + 2. keytool -genkey -alias tomcat -keyalg RSA + Use "changeit" as password ( this is the default we use ) + */ + +/** + * SSL server socket factory. It _requires_ a valid RSA key and + * JSSE. + * + * @author Harish Prabandham + * @author Costin Manolache + * @author Stefan Freyr Stefansson + * @author EKR -- renamed to JSSESocketFactory + * @author Jan Luehe + * @author Bill Barker + */ +public class JSSESocketFactory + extends org.apache.tomcat.util.net.ServerSocketFactory { + + private static StringManager sm = + StringManager.getManager("org.apache.tomcat.util.net.jsse.res"); + + private static final boolean RFC_5746_SUPPORTED; + + // defaults + static String defaultProtocol = "TLS"; + static boolean defaultClientAuth = false; + static String defaultKeystoreType = "JKS"; + private static final String defaultKeystoreFile + = System.getProperty("user.home") + "/.keystore"; + private static final String defaultKeyPass = "changeit"; + private static final int defaultSessionCacheSize = 0; + private static final int defaultSessionTimeout = 86400; + + static org.apache.juli.logging.Log log = + org.apache.juli.logging.LogFactory.getLog(JSSESocketFactory.class); + + static { + boolean result = false; + SSLContext context; + try { + context = SSLContext.getInstance("TLS"); + context.init(null, null, new SecureRandom()); + SSLServerSocketFactory ssf = context.getServerSocketFactory(); + String ciphers[] = ssf.getSupportedCipherSuites(); + for (String cipher : ciphers) { + if ("TLS_EMPTY_RENEGOTIATION_INFO_SCSV".equals(cipher)) { + result = true; + break; + } + } + } catch (NoSuchAlgorithmException e) { + // Assume no RFC 5746 support + } catch (KeyManagementException e) { + // Assume no RFC 5746 support + } + RFC_5746_SUPPORTED = result; + } + + protected boolean initialized; + protected String clientAuth = "false"; + protected SSLServerSocketFactory sslProxy = null; + protected String[] enabledCiphers; + protected boolean allowUnsafeLegacyRenegotiation = false; + + /** + * Flag to state that we require client authentication. + */ + protected boolean requireClientAuth = false; + + /** + * Flag to state that we would like client authentication. + */ + protected boolean wantClientAuth = false; + + + public JSSESocketFactory () { + } + + public ServerSocket createSocket (int port) + throws IOException + { + if (!initialized) init(); + ServerSocket socket = sslProxy.createServerSocket(port); + initServerSocket(socket); + return socket; + } + + public ServerSocket createSocket (int port, int backlog) + throws IOException + { + if (!initialized) init(); + ServerSocket socket = sslProxy.createServerSocket(port, backlog); + initServerSocket(socket); + return socket; + } + + public ServerSocket createSocket (int port, int backlog, + InetAddress ifAddress) + throws IOException + { + if (!initialized) init(); + ServerSocket socket = sslProxy.createServerSocket(port, backlog, + ifAddress); + initServerSocket(socket); + return socket; + } + + public Socket acceptSocket(ServerSocket socket) + throws IOException + { + SSLSocket asock = null; + try { + asock = (SSLSocket)socket.accept(); + configureClientAuth(asock); + } catch (SSLException e){ + throw new SocketException("SSL handshake error" + e.toString()); + } + return asock; + } + + public void handshake(Socket sock) throws IOException { + ((SSLSocket)sock).startHandshake(); + + if (!allowUnsafeLegacyRenegotiation && !RFC_5746_SUPPORTED) { + // Prevent further handshakes by removing all cipher suites + ((SSLSocket) sock).setEnabledCipherSuites(new String[0]); + } + } + + /* + * Determines the SSL cipher suites to be enabled. + * + * @param requestedCiphers Comma-separated list of requested ciphers + * @param supportedCiphers Array of supported ciphers + * + * @return Array of SSL cipher suites to be enabled, or null if none of the + * requested ciphers are supported + */ + protected String[] getEnabledCiphers(String requestedCiphers, + String[] supportedCiphers) { + + String[] enabledCiphers = null; + + if (requestedCiphers != null) { + Vector vec = null; + String cipher = requestedCiphers; + int index = requestedCiphers.indexOf(','); + if (index != -1) { + int fromIndex = 0; + while (index != -1) { + cipher = requestedCiphers.substring(fromIndex, index).trim(); + if (cipher.length() > 0) { + /* + * Check to see if the requested cipher is among the + * supported ciphers, i.e., may be enabled + */ + for (int i=0; supportedCiphers != null + && iPKIX
is supported.
+ *
+ * @param algorithm The algorithm to get parameters for.
+ * @param crlf The path to the CRL file.
+ * @param trustStore The configured TrustStore.
+ * @return The parameters including the CRLs and TrustStore.
+ */
+ protected CertPathParameters getParameters(String algorithm,
+ String crlf,
+ KeyStore trustStore)
+ throws Exception {
+ CertPathParameters params = null;
+ if("PKIX".equalsIgnoreCase(algorithm)) {
+ PKIXBuilderParameters xparams = new PKIXBuilderParameters(trustStore,
+ new X509CertSelector());
+ Collection crls = getCRLs(crlf);
+ CertStoreParameters csp = new CollectionCertStoreParameters(crls);
+ CertStore store = CertStore.getInstance("Collection", csp);
+ xparams.addCertStore(store);
+ xparams.setRevocationEnabled(true);
+ String trustLength = (String)attributes.get("trustMaxCertLength");
+ if(trustLength != null) {
+ try {
+ xparams.setMaxPathLength(Integer.parseInt(trustLength));
+ } catch(Exception ex) {
+ log.warn("Bad maxCertLength: "+trustLength);
+ }
+ }
+
+ params = xparams;
+ } else {
+ throw new CRLException("CRLs not supported for type: "+algorithm);
+ }
+ return params;
+ }
+
+
+ /**
+ * Load the collection of CRLs.
+ *
+ */
+ protected Collection extends CRL> getCRLs(String crlf)
+ throws IOException, CRLException, CertificateException {
+
+ File crlFile = new File(crlf);
+ if( !crlFile.isAbsolute() ) {
+ crlFile = new File(System.getProperty("catalina.base"), crlf);
+ }
+ Collection extends CRL> crls = null;
+ InputStream is = null;
+ try {
+ CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ is = new FileInputStream(crlFile);
+ crls = cf.generateCRLs(is);
+ } catch(IOException iex) {
+ throw iex;
+ } catch(CRLException crle) {
+ throw crle;
+ } catch(CertificateException ce) {
+ throw ce;
+ } finally {
+ if(is != null) {
+ try{
+ is.close();
+ } catch(Exception ex) {
+ }
+ }
+ }
+ return crls;
+ }
+
+ /**
+ * Set the SSL protocol variants to be enabled.
+ * @param socket the SSLServerSocket.
+ * @param protocols the protocols to use.
+ */
+ protected void setEnabledProtocols(SSLServerSocket socket, String []protocols){
+ if (protocols != null) {
+ socket.setEnabledProtocols(protocols);
+ }
+ }
+
+ /**
+ * Determines the SSL protocol variants to be enabled.
+ *
+ * @param socket The socket to get supported list from.
+ * @param requestedProtocols Comma-separated list of requested SSL
+ * protocol variants
+ *
+ * @return Array of SSL protocol variants to be enabled, or null if none of
+ * the requested protocol variants are supported
+ */
+ protected String[] getEnabledProtocols(SSLServerSocket socket,
+ String requestedProtocols){
+ String[] supportedProtocols = socket.getSupportedProtocols();
+
+ String[] enabledProtocols = null;
+
+ if (requestedProtocols != null) {
+ Vector vec = null;
+ String protocol = requestedProtocols;
+ int index = requestedProtocols.indexOf(',');
+ if (index != -1) {
+ int fromIndex = 0;
+ while (index != -1) {
+ protocol = requestedProtocols.substring(fromIndex, index).trim();
+ if (protocol.length() > 0) {
+ /*
+ * Check to see if the requested protocol is among the
+ * supported protocols, i.e., may be enabled
+ */
+ for (int i=0; supportedProtocols != null
+ && iorg.apache.catalina.valves.CertificateValve
+ */
+ public Integer getKeySize()
+ throws IOException {
+ // Look up the current SSLSession
+ SSLSupport.CipherData c_aux[]=ciphers;
+ if (session == null)
+ return null;
+
+ Integer keySize = null;
+ synchronized(keySizeCache) {
+ keySize = keySizeCache.get(session);
+ }
+
+ if (keySize == null) {
+ int size = 0;
+ String cipherSuite = session.getCipherSuite();
+ for (int i = 0; i < c_aux.length; i++) {
+ if (cipherSuite.indexOf(c_aux[i].phrase) >= 0) {
+ size = c_aux[i].keySize;
+ break;
+ }
+ }
+ keySize = new Integer(size);
+ synchronized(keySizeCache) {
+ keySizeCache.put(session, keySize);
+ }
+ }
+ return keySize;
+ }
+
+ public String getSessionId()
+ throws IOException {
+ // Look up the current SSLSession
+ if (session == null)
+ return null;
+ // Expose ssl_session (getId)
+ byte [] ssl_session = session.getId();
+ if ( ssl_session == null)
+ return null;
+ StringBuffer buf=new StringBuffer("");
+ for(int x=0; x