| // |
| // ======================================================================== |
| // Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd. |
| // ------------------------------------------------------------------------ |
| // All rights reserved. This program and the accompanying materials |
| // are made available under the terms of the Eclipse Public License v1.0 |
| // and Apache License v2.0 which accompanies this distribution. |
| // |
| // The Eclipse Public License is available at |
| // http://www.eclipse.org/legal/epl-v10.html |
| // |
| // The Apache License v2.0 is available at |
| // http://www.opensource.org/licenses/apache2.0.php |
| // |
| // You may elect to redistribute this code under either of these licenses. |
| // ======================================================================== |
| // |
| |
| package org.eclipse.jetty.npn; |
| |
| import java.util.List; |
| import java.util.Map; |
| import java.util.concurrent.ConcurrentHashMap; |
| import javax.net.ssl.SSLEngine; |
| import javax.net.ssl.SSLSocket; |
| |
| /** |
| * <p>{@link NextProtoNego} provides an API to applications that want to make use of the |
| * <a href="https://tools.ietf.org/html/draft-agl-tls-nextprotoneg">Next Protocol Negotiation</a>.</p> |
| * <p>The NPN extension is only available when using the TLS protocol, therefore applications must |
| * ensure that the TLS protocol is used:</p> |
| * <pre> |
| * SSLContext context = SSLContext.getInstance("TLSv1"); |
| * </pre> |
| * <p>Refer to the |
| * <a href="http://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#SSLContext">list |
| * of standard SSLContext protocol names</a> for further information on TLS protocol versions supported.</p> |
| * <p>Applications must register instances of either {@link SSLSocket} or {@link SSLEngine} with a |
| * {@link ClientProvider} or with a {@link ServerProvider}, depending whether they are on client or |
| * server side.</p> |
| * <p>The NPN implementation will invoke the provider callbacks to allow applications to interact |
| * with the negotiation of the next protocol.</p> |
| * <p>Client side typical usage:</p> |
| * <pre> |
| * final SSLSocket sslSocket = ...; |
| * NextProtoNego.put(sslSocket, new NextProtoNego.ClientProvider() |
| * { |
| * @Override |
| * public boolean supports() |
| * { |
| * return true; |
| * } |
| * |
| * @Override |
| * public void unsupported() |
| * { |
| * NextProtoNego.remove(sslSocket); |
| * } |
| * |
| * @Override |
| * public String selectProtocol(List<String> protocols) |
| * { |
| * NextProtoNego.remove(sslSocket); |
| * return protocols.get(0); |
| * } |
| * }); |
| * </pre> |
| * <p>Server side typical usage:</p> |
| * <pre> |
| * final SSLSocket sslSocket = ...; |
| * NextProtoNego.put(sslSocket, new NextProtoNego.ServerProvider() |
| * { |
| * @Override |
| * public void unsupported() |
| * { |
| * NextProtoNego.remove(sslSocket); |
| * } |
| * |
| * @Override |
| * public List<String> protocols() |
| * { |
| * return Arrays.asList("http/1.1"); |
| * } |
| * |
| * @Override |
| * public void protocolSelected(String protocol) |
| * { |
| * NextProtoNego.remove(sslSocket); |
| * System.out.println("Protocol Selected is: " + protocol); |
| * } |
| * }); |
| * </pre> |
| * <p>The implementation must make sure to remove the {@link SSLSocket} or {@link SSLEngine} |
| * instances when the NPN interaction is completed.</p> |
| * <p>In order to help application development, you can set the {@link NextProtoNego#debug} field |
| * to {@code true} to have debug code printed to {@link System#err}.</p> |
| */ |
| public class NextProtoNego |
| { |
| /** |
| * <p>Enables debug logging on {@link System#err}.</p> |
| */ |
| public static boolean debug = false; |
| |
| private static final Map<Object, Provider> objects = new ConcurrentHashMap<>(); |
| |
| private NextProtoNego() |
| { |
| } |
| |
| /** |
| * <p>Registers a SSLSocket with a provider.</p> |
| * |
| * @param socket the socket to register with the provider |
| * @param provider the provider to register with the socket |
| * @see #remove(SSLSocket) |
| */ |
| public static void put(SSLSocket socket, Provider provider) |
| { |
| objects.put(socket, provider); |
| } |
| |
| /** |
| * @param socket a socket registered with {@link #put(SSLSocket, Provider)} |
| * @return the provider registered with the given socket |
| */ |
| public static Provider get(SSLSocket socket) |
| { |
| return objects.get(socket); |
| } |
| |
| /** |
| * <p>Unregisters the given SSLSocket.</p> |
| * |
| * @param socket the socket to unregister |
| * @return the provider registered with the socket |
| * @see #put(SSLSocket, Provider) |
| */ |
| public static Provider remove(SSLSocket socket) |
| { |
| return objects.remove(socket); |
| } |
| |
| /** |
| * <p>Registers a SSLEngine with a provider.</p> |
| * |
| * @param engine the engine to register with the provider |
| * @param provider the provider to register with the engine |
| * @see #remove(SSLEngine) |
| */ |
| public static void put(SSLEngine engine, Provider provider) |
| { |
| objects.put(engine, provider); |
| } |
| |
| /** |
| * @param engine an engine registered with {@link #put(SSLEngine, Provider)} |
| * @return the provider registered with the given engine |
| */ |
| public static Provider get(SSLEngine engine) |
| { |
| return objects.get(engine); |
| } |
| |
| /** |
| * <p>Unregisters the given SSLEngine.</p> |
| * |
| * @param engine the engine to unregister |
| * @return the provider registered with the engine |
| * @see #put(SSLEngine, Provider) |
| */ |
| public static Provider remove(SSLEngine engine) |
| { |
| return objects.remove(engine); |
| } |
| |
| /** |
| * <p>Base, empty, interface for providers.</p> |
| */ |
| public interface Provider |
| { |
| } |
| |
| /** |
| * <p>The client-side provider interface that applications must implement to interact |
| * with the negotiation of the next protocol.</p> |
| */ |
| public interface ClientProvider extends Provider |
| { |
| /** |
| * <p>Callback invoked to let the implementation know whether an |
| * empty NPN extension should be added to a ClientHello SSL message.</p> |
| * |
| * @return true to add the NPN extension, false otherwise |
| */ |
| public boolean supports(); |
| |
| /** |
| * <p>Callback invoked to let the application know that the server does |
| * not support NPN.</p> |
| */ |
| public void unsupported(); |
| |
| /** |
| * <p>Callback invoked to let the application select a protocol |
| * among the ones sent by the server.</p> |
| * <p>The implementation may return null to indicate to the server that |
| * it was not possible to negotiate a protocol.</p> |
| * <p>The implementation may throw an exception to indicate that the |
| * TLS handshake must be aborted.</p> |
| * |
| * @param protocols the protocols sent by the server |
| * @return the protocol selected by the application, or {@code null} |
| * to indicate to the server that it was not possible to negotiate |
| * a protocol |
| */ |
| public String selectProtocol(List<String> protocols); |
| } |
| |
| /** |
| * <p>The server-side provider interface that applications must implement to interact |
| * with the negotiation of the next protocol.</p> |
| */ |
| public interface ServerProvider extends Provider |
| { |
| /** |
| * <p>Callback invoked to let the application know that the client does not |
| * support NPN.</p> |
| */ |
| public void unsupported(); |
| |
| /** |
| * <p>Callback invoked to let the implementation know the list |
| * of protocols that should be added to an NPN extension in a |
| * ServerHello SSL message.</p> |
| * <p>This callback is invoked only if the client sent a NPN extension.</p> |
| * |
| * @return the list of protocols, or null if no NPN extension |
| * should be sent to the client |
| */ |
| public List<String> protocols(); |
| |
| /** |
| * <p>Callback invoked to let the application know the protocol selected |
| * by the client.</p> |
| * <p>The protocol selected may be {@code null} if the client could not |
| * negotiate a protocol.</p> |
| * <p>The implementation may throw an exception to indicate that the TLS |
| * handshake must be aborted.</p> |
| * |
| * @param protocol the selected protocol, or {@code null} if the client |
| * could not negotiate a protocol |
| */ |
| public void protocolSelected(String protocol); |
| } |
| } |