blob: 10d23d1ef45201658d3888aac22250739325fd2d [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed 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.conscrypt;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.security.KeyManagementException;
import java.security.PrivateKey;
import java.security.Provider;
import javax.net.ssl.SSLContextSpi;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLEngineResult;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509TrustManager;
/**
* Core API for creating and configuring all Conscrypt types.
*/
public final class Conscrypt {
private Conscrypt() {}
/**
* Constructs a new {@link Provider} with the default name.
*/
public static Provider newProvider() {
return new OpenSSLProvider();
}
/**
* Constructs a new {@link Provider} with the given name.
*/
public static Provider newProvider(String providerName) {
return new OpenSSLProvider(providerName);
}
/**
* Constructs a new instance of the preferred {@link SSLContextSpi}.
*/
public static SSLContextSpi newPreferredSSLContextSpi() {
return OpenSSLContextImpl.getPreferred();
}
/**
* Gets the default X.509 trust manager.
*/
@ExperimentalApi
public static X509TrustManager getDefaultX509TrustManager() throws KeyManagementException {
return SSLParametersImpl.getDefaultX509TrustManager();
}
/**
* Utility that exposes common TLS constants.
*/
@ExperimentalApi
public static final class Constants {
private Constants() {}
/**
* Returns the maximum length (in bytes) of an encrypted packet.
*/
public static int maxEncryptedPacketLength() {
return NativeConstants.SSL3_RT_MAX_PACKET_SIZE;
}
}
/**
* Utility methods for configuring Conscrypt socket factories.
*/
public static final class SocketFactories {
private SocketFactories() {}
/**
* Indicates whether the given object is a Conscrypt socket factory.
*/
public static boolean isConscrypt(SSLSocketFactory factory) {
return factory instanceof OpenSSLSocketFactoryImpl;
}
private static OpenSSLSocketFactoryImpl toConscrypt(SSLSocketFactory factory) {
if (!isConscrypt(factory)) {
throw new IllegalArgumentException(
"Not a conscrypt socket factory: " + factory.getClass().getName());
}
return (OpenSSLSocketFactoryImpl) factory;
}
/**
* Configures the default socket to be created for all socket factory instances.
*/
@ExperimentalApi
public static void setUseEngineSocketByDefault(boolean useEngineSocket) {
OpenSSLSocketFactoryImpl.setUseEngineSocketByDefault(useEngineSocket);
}
/**
* Configures the socket to be created for the given socket factory instance.
*/
@ExperimentalApi
public static void setUseEngineSocket(SSLSocketFactory factory, boolean useEngineSocket) {
toConscrypt(factory).setUseEngineSocket(useEngineSocket);
}
}
/**
* Utility methods for configuring Conscrypt server socket factories.
*/
public static final class ServerSocketFactories {
private ServerSocketFactories() {}
/**
* Indicates whether the given object is a Conscrypt socket factory.
*/
public static boolean isConscrypt(SSLServerSocketFactory factory) {
return factory instanceof OpenSSLServerSocketFactoryImpl;
}
private static OpenSSLServerSocketFactoryImpl toConscrypt(SSLServerSocketFactory factory) {
if (!isConscrypt(factory)) {
throw new IllegalArgumentException(
"Not a conscrypt server socket factory: " + factory.getClass().getName());
}
return (OpenSSLServerSocketFactoryImpl) factory;
}
/**
* Configures the default socket to be created for all server socket factory instances.
*/
@ExperimentalApi
public static void setUseEngineSocketByDefault(boolean useEngineSocket) {
OpenSSLServerSocketFactoryImpl.setUseEngineSocketByDefault(useEngineSocket);
}
/**
* Configures the socket to be created for the given server socket factory instance.
*/
@ExperimentalApi
public static void setUseEngineSocket(
SSLServerSocketFactory factory, boolean useEngineSocket) {
toConscrypt(factory).setUseEngineSocket(useEngineSocket);
}
}
/**
* Utility methods for configuring Conscrypt sockets.
*/
public static final class Sockets {
private Sockets() {}
/**
* Indicates whether the given socket is a Conscrypt socket.
*/
public static boolean isConscrypt(SSLSocket socket) {
return socket instanceof AbstractConscryptSocket;
}
private static AbstractConscryptSocket toConscrypt(SSLSocket socket) {
if (!isConscrypt(socket)) {
throw new IllegalArgumentException(
"Not a conscrypt socket: " + socket.getClass().getName());
}
return (AbstractConscryptSocket) socket;
}
/**
* This method enables Server Name Indication (SNI) and overrides the hostname supplied
* during socket creation.
*
* @param socket the socket
* @param hostname the desired SNI hostname, or null to disable
*/
public static void setHostname(SSLSocket socket, String hostname) {
toConscrypt(socket).setHostname(hostname);
}
/**
* Returns either the hostname supplied during socket creation or via
* {@link #setHostname(SSLSocket, String)}. No DNS resolution is attempted before
* returning the hostname.
*/
public static String getHostname(SSLSocket socket) {
return toConscrypt(socket).getHostname();
}
/**
* This method attempts to create a textual representation of the peer host or IP. Does
* not perform a reverse DNS lookup. This is typically used during session creation.
*/
public static String getHostnameOrIP(SSLSocket socket) {
return toConscrypt(socket).getHostnameOrIP();
}
/**
* This method enables session ticket support.
*
* @param socket the socket
* @param useSessionTickets True to enable session tickets
*/
public static void setUseSessionTickets(SSLSocket socket, boolean useSessionTickets) {
toConscrypt(socket).setUseSessionTickets(useSessionTickets);
}
/**
* Enables/disables TLS Channel ID for the given server-side socket.
*
* <p>This method needs to be invoked before the handshake starts.
*
* @param socket the socket
* @param enabled Whether to enable channel ID.
* @throws IllegalStateException if this is a client socket or if the handshake has already
* started.
*/
public static void setChannelIdEnabled(SSLSocket socket, boolean enabled) {
toConscrypt(socket).setChannelIdEnabled(enabled);
}
/**
* Gets the TLS Channel ID for the given server-side socket. Channel ID is only available
* once the handshake completes.
*
* @param socket the socket
* @return channel ID or {@code null} if not available.
* @throws IllegalStateException if this is a client socket or if the handshake has not yet
* completed.
* @throws SSLException if channel ID is available but could not be obtained.
*/
public static byte[] getChannelId(SSLSocket socket) throws SSLException {
return toConscrypt(socket).getChannelId();
}
/**
* Sets the {@link PrivateKey} to be used for TLS Channel ID by this client socket.
*
* <p>This method needs to be invoked before the handshake starts.
*
* @param socket the socket
* @param privateKey private key (enables TLS Channel ID) or {@code null} for no key
* (disables TLS Channel ID).
* The private key must be an Elliptic Curve (EC) key based on the NIST P-256 curve (aka
* SECG secp256r1 or ANSI
* X9.62 prime256v1).
* @throws IllegalStateException if this is a server socket or if the handshake has already
* started.
*/
public static void setChannelIdPrivateKey(SSLSocket socket, PrivateKey privateKey) {
toConscrypt(socket).setChannelIdPrivateKey(privateKey);
}
/**
* Returns the ALPN protocol agreed upon by client and server.
*
* @param socket the socket
* @return the selected protocol or {@code null} if no protocol was agreed upon.
*/
public static String getAlpnSelectedProtocol(SSLSocket socket) {
return toProtocolString(toConscrypt(socket).getAlpnSelectedProtocol());
}
/**
* Sets the list of ALPN protocols supported by the socket.
*
* @param socket the socket
* @param alpnProtocols the list of ALPN protocols
*/
public static void setAlpnProtocols(SSLSocket socket, String[] alpnProtocols) {
toConscrypt(socket).setAlpnProtocols(alpnProtocols);
}
}
/**
* Utility methods for configuring Conscrypt engines.
*/
public static final class Engines {
private Engines() {}
/**
* Indicates whether the given engine is a Conscrypt engine.
*/
public static boolean isConscrypt(SSLEngine engine) {
return engine instanceof ConscryptEngine;
}
private static ConscryptEngine toConscrypt(SSLEngine engine) {
if (!isConscrypt(engine)) {
throw new IllegalArgumentException(
"Not a conscrypt engine: " + engine.getClass().getName());
}
return (ConscryptEngine) engine;
}
/**
* This method enables Server Name Indication (SNI) and overrides the hostname supplied
* during engine creation.
*
* @param engine the engine
* @param hostname the desired SNI hostname, or {@code null} to disable
*/
public static void setHostname(SSLEngine engine, String hostname) {
toConscrypt(engine).setHostname(hostname);
}
/**
* Returns either the hostname supplied during socket creation or via
* {@link #setHostname(SSLEngine, String)}. No DNS resolution is attempted before
* returning the hostname.
*/
public static String getHostname(SSLEngine engine) {
return toConscrypt(engine).getHostname();
}
/**
* Returns the maximum overhead, in bytes, of sealing a record with SSL.
*/
public static int maxSealOverhead(SSLEngine engine) {
return toConscrypt(engine).maxSealOverhead();
}
/**
* Sets a listener on the given engine for completion of the TLS handshake
*/
public static void setHandshakeListener(
SSLEngine engine, HandshakeListener handshakeListener) {
toConscrypt(engine).setHandshakeListener(handshakeListener);
}
/**
* Enables/disables TLS Channel ID for the given server-side engine.
*
* <p>This method needs to be invoked before the handshake starts.
*
* @param engine the engine
* @param enabled Whether to enable channel ID.
* @throws IllegalStateException if this is a client engine or if the handshake has already
* started.
*/
public static void setChannelIdEnabled(SSLEngine engine, boolean enabled) {
toConscrypt(engine).setChannelIdEnabled(enabled);
}
/**
* Gets the TLS Channel ID for the given server-side engine. Channel ID is only available
* once the handshake completes.
*
* @param engine the engine
* @return channel ID or {@code null} if not available.
* @throws IllegalStateException if this is a client engine or if the handshake has not yet
* completed.
* @throws SSLException if channel ID is available but could not be obtained.
*/
public static byte[] getChannelId(SSLEngine engine) throws SSLException {
return toConscrypt(engine).getChannelId();
}
/**
* Sets the {@link PrivateKey} to be used for TLS Channel ID by this client engine.
*
* <p>This method needs to be invoked before the handshake starts.
*
* @param engine the engine
* @param privateKey private key (enables TLS Channel ID) or {@code null} for no key
* (disables TLS Channel ID).
* The private key must be an Elliptic Curve (EC) key based on the NIST P-256 curve (aka
* SECG secp256r1 or ANSI X9.62 prime256v1).
* @throws IllegalStateException if this is a server engine or if the handshake has already
* started.
*/
public static void setChannelIdPrivateKey(SSLEngine engine, PrivateKey privateKey) {
toConscrypt(engine).setChannelIdPrivateKey(privateKey);
}
/**
* Extended unwrap method for multiple source and destination buffers.
*
* @param engine the target engine for the unwrap
* @param srcs the source buffers
* @param dsts the destination buffers
* @return the result of the unwrap operation
* @throws SSLException thrown if an SSL error occurred
*/
public static SSLEngineResult unwrap(SSLEngine engine, final ByteBuffer[] srcs,
final ByteBuffer[] dsts) throws SSLException {
return toConscrypt(engine).unwrap(srcs, dsts);
}
/**
* Exteneded unwrap method for multiple source and destination buffers.
*
* @param engine the target engine for the unwrap.
* @param srcs the source buffers
* @param srcsOffset the offset in the {@code srcs} array of the first source buffer
* @param srcsLength the number of source buffers starting at {@code srcsOffset}
* @param dsts the destination buffers
* @param dstsOffset the offset in the {@code dsts} array of the first destination buffer
* @param dstsLength the number of destination buffers starting at {@code dstsOffset}
* @return the result of the unwrap operation
* @throws SSLException thrown if an SSL error occurred
*/
public static SSLEngineResult unwrap(SSLEngine engine, final ByteBuffer[] srcs,
int srcsOffset, final int srcsLength, final ByteBuffer[] dsts, final int dstsOffset,
final int dstsLength) throws SSLException {
return toConscrypt(engine).unwrap(
srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength);
}
/**
* This method enables session ticket support.
*
* @param engine the engine
* @param useSessionTickets True to enable session tickets
*/
public static void setUseSessionTickets(SSLEngine engine, boolean useSessionTickets) {
toConscrypt(engine).setUseSessionTickets(useSessionTickets);
}
/**
* Sets the list of ALPN protocols supported by the engine.
*
* @param engine the engine
* @param alpnProtocols the list of ALPN protocols
*/
public static void setAlpnProtocols(SSLEngine engine, String[] alpnProtocols) {
toConscrypt(engine).setAlpnProtocols(alpnProtocols);
}
/**
* Returns the ALPN protocol agreed upon by client and server.
*
* @param engine the engine
* @return the selected protocol or {@code null} if no protocol was agreed upon.
*/
public static String getAlpnSelectedProtocol(SSLEngine engine) {
return toProtocolString(toConscrypt(engine).getAlpnSelectedProtocol());
}
}
private static String toProtocolString(byte[] bytes) {
try {
if (bytes == null) {
return null;
}
return new String(bytes, "US-ASCII");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
}