All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.mongodb.internal.connection.tlschannel.TlsChannel Maven / Gradle / Ivy

Go to download

The MongoDB Java Driver uber-artifact, containing mongodb-driver, mongodb-driver-core, and bson

The newest version!
/*
 * Copyright 2008-present MongoDB, Inc.
 *
 * 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.
 *
 * Original Work: MIT License, Copyright (c) [2015-2018] all contributors
 * https://github.com/marianobarrios/tls-channel
 */

package com.mongodb.internal.connection.tlschannel;

import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.ByteChannel;
import java.nio.channels.GatheringByteChannel;
import java.nio.channels.ScatteringByteChannel;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.function.Consumer;

/**
 * A ByteChannel interface to a TLS (Transport Layer Security) connection.
 *
 * 

* Instances that implement this interface delegate all cryptographic operations * to the standard Java TLS implementation: SSLEngine; effectively hiding it * behind an easy-to-use streaming API, that allows to securitize JVM * applications with minimal added complexity. * *

* In other words, an interface that allows the programmer to have TLS using the * same standard socket API used for plaintext, just like OpenSSL does for C, * only for Java. * *

* Note that this is an API adapter, not a cryptographic implementation: with * the exception of a few bytesProduced of parsing at the beginning of the connection, * to look for the SNI, the whole protocol implementation is done by the * SSLEngine. Both the SSLContext and SSLEngine are supplied by the client; * these classes are the ones responsible for protocol configuration, including * hostname validation, client-side authentication, etc. * *

* A TLS channel is created by using one of its subclasses. They will * take an existing {@link ByteChannel} (typically, but not necessarily, a * {@link SocketChannel}) and a {@link SSLEngine}. * *

* It should be noted that this interface extends {@link ByteChannel} as a * design compromise, but it does not follow its interface completely. In * particular, in case of underlying non-blocking channels, when it is not * possible to complete an operation, no zero is returned, but an * {@link WouldBlockException}. This divergence from the base interface is * needed because both a read and a write operation * can run out of both bytesProduced for reading and buffer space for writing, as a * handshake (a bidirectional operation) can happen at any moment. The user * would use a {@link Selector} to wait for the expected condition * of the underlying channel, and should know which operation to * register. * *

* On top of that, operations can also fail to complete due to asynchronous * tasks; this is communicated using a {@link NeedsTaskException}. This behavior * is controlled by the {@link #getRunTasks()} attribute. This allows the user * to execute CPU-intensive tasks out of the selector loop. */ public interface TlsChannel extends ByteChannel, GatheringByteChannel, ScatteringByteChannel { /** * Return a reference to the underlying {@link ByteChannel}. */ ByteChannel getUnderlying(); /** * Return a reference to the {@link SSLEngine} used. * * @return the engine reference if present, or null if unknown * (that can happen in server-side channels before the SNI is * parsed). */ SSLEngine getSslEngine(); /** * Return the callback function to be executed when the TLS session is * established (or re-established). * * @see TlsChannelBuilder#withSessionInitCallback(Consumer) */ Consumer getSessionInitCallback(); /** * Return the {@link BufferAllocator} to use for unencrypted data. Actually, a decorating subclass is returned, * which contains allocation statistics for this channel. * * @see TlsChannelBuilder#withPlainBufferAllocator(BufferAllocator) * @see TrackingAllocator */ TrackingAllocator getPlainBufferAllocator(); /** * Return the {@link BufferAllocator} to use for encrypted data. Actually, a decorating subclass is returned, * which contains allocation statistics for this channel. * * @see TlsChannelBuilder#withEncryptedBufferAllocator(BufferAllocator) * @see TrackingAllocator */ TrackingAllocator getEncryptedBufferAllocator(); /** * Return whether CPU-intensive tasks are run or not. * * @see TlsChannelBuilder#withRunTasks(boolean) */ boolean getRunTasks(); /** * Reads a sequence of bytesProduced from this channel into the given buffer. * *

* An attempt is made to read up to r bytesProduced from the channel, where * r is the number of bytesProduced remaining in the buffer, that is, * dst.remaining(), at the moment this method is invoked. * *

* Suppose that a byte sequence of length n is read, where 0 *  <= n <= r. * This byte sequence will be transferred into the buffer so that the first * byte in the sequence is at index p and the last byte is at index * p + n - 1, * where p is the buffer's position at the moment this method is * invoked. Upon return the buffer's position will be equal to p *  + n; its limit will not have changed. * *

* A read operation might not fill the buffer, and in fact it might not read * any bytesProduced at all. Whether or not it does so depends upon the nature and * state of the underlying channel. It is guaranteed, however, that if a * channel is in blocking mode and there is at least one byte remaining in * the buffer then this method will block until at least one byte is read. * On the other hand, if the underlying channel is in non-blocking mode then * a {@link WouldBlockException} may be thrown. Note that this also includes * the possibility of a {@link NeedsWriteException}, due to the fact that, * during a TLS handshake, bytesProduced need to be written to the underlying * channel. In any case, after a {@link WouldBlockException}, the operation * should be retried when the underlying channel is ready (for reading or * writing, depending on the subclass). * *

* If the channel is configured to not run tasks and one is due to run, a * {@link NeedsTaskException} will be thrown. In this case the operation * should be retried after the task is run. * *

* This method may be invoked at any time. If another thread has already * initiated a read or handshaking operation upon this channel, however, * then an invocation of this method will block until the first operation is * complete. * * @param dst The buffer into which bytesProduced are to be transferred * @return The number of bytesProduced read, or -1 if the channel has * reached end-of-stream; contrary to the behavior specified in * {@link ByteChannel}, this method never returns 0, but throws * {@link WouldBlockException} * @throws WouldBlockException if the channel is in non-blocking mode and the IO operation * cannot be completed immediately * @throws NeedsTaskException if the channel is not configured to run tasks automatically * and a task needs to be executed to complete the operation * @throws SSLException if the {@link SSLEngine} throws a SSLException * @throws IOException if the underlying channel throws an IOException */ int read(ByteBuffer dst) throws IOException; /** * Writes a sequence of bytesProduced to this channel from the given buffer. * *

* An attempt is made to write up to r bytesProduced to the channel, where * r is the number of bytesProduced remaining in the buffer, that is, * src.remaining(), at the moment this method is invoked. * *

* Suppose that a byte sequence of length n is written, where * 0 <= n <=  * r. This byte sequence will be transferred from the buffer starting * at index p, where p is the buffer's position at the moment * this method is invoked; the index of the last byte written will be * p + n - 1. * Upon return the buffer's position will be equal to p  * + n; its limit will not have changed. * *

* If the underlying channel is in blocking mode, a write operation will * return only after writing all of the r requested bytesProduced. On the * other hand, if it is in non-blocking mode, this operation may write only * some of the bytesProduced or possibly none at all, in this case a * {@link WouldBlockException} will be thrown. Note that this also includes * the possibility of a {@link NeedsReadException}, due to the fact that, * during a TLS handshake, bytes need to be read from the underlying channel. * In any case, after a {@link WouldBlockException}, the operation should be * retried when the underlying channel is ready (for reading or writing, * depending on the subclass). * *

* If the channel is configured to not run tasks and one is due to run, a * {@link NeedsTaskException} will be thrown. In this case the operation * should be retried after the task is run. * *

* This method may be invoked at any time. If another thread has already * initiated a write or handshaking operation upon this channel, however, * then an invocation of this method will block until the first operation is * complete. * * @param src The buffer from which bytesProduced are to be retrieved * @return The number of bytesProduced written, contrary to the behavior specified * in {@link ByteChannel}, this method never returns 0, but throws * {@link WouldBlockException} * @throws WouldBlockException if the channel is in non-blocking mode and the IO operation * cannot be completed immediately * @throws NeedsTaskException if the channel is not configured to run tasks automatically * and a task needs to be executed to complete the operation * @throws SSLException if the {@link SSLEngine} throws a SSLException * @throws IOException if the underlying channel throws an IOException */ int write(ByteBuffer src) throws IOException; /** * Initiates a handshake (initial or renegotiation) on this channel. This * method is not needed for the initial handshake, as the * read() and write() methods will implicitly do * the initial handshake if needed. * *

* This method may block if the underlying channel if in blocking mode. * *

* Note that renegotiation is a problematic feature of the TLS protocol, * that should only be initiated at quiet point of the protocol. * *

* This method may block if the underlying channel is in blocking mode, * otherwise a {@link WouldBlockException} can be thrown. In this case the * operation should be retried when the underlying channel is ready (for * reading or writing, depending on the subclass). * *

* If the channel is configured to not run tasks and one is due to run, a * {@link NeedsTaskException} will be thrown, with a reference to the task. * In this case the operation should be retried after the task is run. * *

* This method may be invoked at any time. If another thread has already * initiated a read, write, or handshaking operation upon this channel, * however, then an invocation of this method will block until the first * operation is complete. * * @throws WouldBlockException if the channel is in non-blocking mode and the IO operation * cannot be completed immediately * @throws NeedsTaskException if the channel is not configured to run tasks automatically * and a task needs to be executed to complete the operation * @throws SSLException if the {@link SSLEngine} throws a SSLException * @throws IOException if the underlying channel throws an IOException */ void renegotiate() throws IOException; /** * Forces the initial TLS handshake. Calling this method is usually not * needed, as a handshake will happen automatically when doing the first * read() or write() operation. Calling this * method after the initial handshake has been done has no effect. * *

* This method may block if the underlying channel is in blocking mode, * otherwise a {@link WouldBlockException} can be thrown. In this case the * operation should be retried when the underlying channel is ready (for * reading or writing, depending on the subclass). * *

* If the channel is configured to not run tasks and one is due to run, a * {@link NeedsTaskException} will be thrown, with a reference to the task. * In this case the operation should be retried after the task is run. * *

* This method may be invoked at any time. If another thread has already * initiated a read, write, or handshaking operation upon this channel, * however, then an invocation of this method will block until the first * operation is complete. * * @throws WouldBlockException if the channel is in non-blocking mode and the IO operation * cannot be completed immediately * @throws NeedsTaskException if the channel is not configured to run tasks automatically * and a task needs to be executed to complete the operation * @throws SSLException if the {@link SSLEngine} throws a SSLException * @throws IOException if the underlying channel throws an IOException */ void handshake() throws IOException; /** * Writes a sequence of bytesProduced to this channel from a subsequence of the * given buffers. * *

* See {@link GatheringByteChannel#write(ByteBuffer[], int, int)} for more * details of the meaning of this signature. * *

* This method behaves slightly different than the interface specification, * with respect to non-blocking responses, see {@link #write(ByteBuffer)} * for more details. * * @param srcs The buffers from which bytesProduced are to be retrieved * @param offset The offset within the buffer array of the first buffer from * which bytesProduced are to be retrieved; must be non-negative and no * larger than srcs.length * @param length The maximum number of buffers to be accessed; must be * non-negative and no larger than srcs.length *  - offset * @return The number of bytesProduced written, contrary to the behavior specified * in {@link ByteChannel}, this method never returns 0, but throws * {@link WouldBlockException} * @throws IndexOutOfBoundsException If the preconditions on the offset and * length parameters do not hold * @throws WouldBlockException if the channel is in non-blocking mode and the IO operation * cannot be completed immediately * @throws NeedsTaskException if the channel is not configured to run tasks automatically * and a task needs to be executed to complete the operation * @throws SSLException if the {@link SSLEngine} throws a SSLException * @throws IOException if the underlying channel throws an IOException */ long write(ByteBuffer[] srcs, int offset, int length) throws IOException; /** * Writes a sequence of bytesProduced to this channel from the given buffers. * *

* An invocation of this method of the form c.write(srcs) behaves * in exactly the same manner as the invocation * *

* *
     * c.write(srcs, 0, srcs.length);
     * 
* *
*

* This method behaves slightly different than the interface specification, * with respect to non-blocking responses, see {@link #write(ByteBuffer)} * for more details. * * @param srcs The buffers from which bytesProduced are to be retrieved * @return The number of bytesProduced written, contrary to the behavior specified * in {@link ByteChannel}, this method never returns 0, but throws * {@link WouldBlockException} * @throws IndexOutOfBoundsException If the preconditions on the offset and * length parameters do not hold * @throws WouldBlockException if the channel is in non-blocking mode and the IO operation * cannot be completed immediately * @throws NeedsTaskException if the channel is not configured to run tasks automatically * and a task needs to be executed to complete the operation * @throws SSLException if the {@link SSLEngine} throws a SSLException * @throws IOException if the underlying channel throws an IOExceptions */ long write(ByteBuffer[] srcs) throws IOException; /** * Reads a sequence of bytesProduced from this channel into a subsequence of the * given buffers. * *

* See {@link ScatteringByteChannel#read(ByteBuffer[], int, int)} for more * details of the meaning of this signature. * *

* This method behaves slightly different than the interface specification, * with respect to non-blocking responses, see {@link #read(ByteBuffer)} for * more details. * * @param dsts The buffers into which bytesProduced are to be transferred * @param offset The offset within the buffer array of the first buffer into * which bytesProduced are to be transferred; must be non-negative and no * larger than dsts.length * @param length The maximum number of buffers to be accessed; must be * non-negative and no larger than dsts.length *  - offset * @return The number of bytesProduced read, or -1 if the channel has * reached end-of-stream; contrary to the behavior specified in * {@link ByteChannel}, this method never returns 0, but throws * {@link WouldBlockException} * @throws IndexOutOfBoundsException If the preconditions on the offset and * length parameters do not hold * @throws WouldBlockException if the channel is in non-blocking mode and the IO operation * cannot be completed immediately * @throws NeedsTaskException if the channel is not configured to run tasks automatically * and a task needs to be executed to complete the operation * @throws SSLException if the {@link SSLEngine} throws a SSLException * @throws IOException if the underlying channel throws an IOException */ long read(ByteBuffer[] dsts, int offset, int length) throws IOException; /** * Reads a sequence of bytesProduced from this channel into the given buffers. * *

* An invocation of this method of the form c.read(dsts) behaves in * exactly the same manner as the invocation * *

* *
     * c.read(dsts, 0, dsts.length);
     * 
* *
* *

* This method behaves slightly different than the interface specification, * with respect to non-blocking responses, see {@link #read(ByteBuffer)} for * more details. * * @param dsts The buffers into which bytesProduced are to be transferred * @return The number of bytesProduced read, or -1 if the channel has * reached end-of-stream; contrary to the behavior specified in * {@link ByteChannel}, this method never returns 0, but throws * {@link WouldBlockException} * @throws IndexOutOfBoundsException If the preconditions on the offset and * length parameters do not hold * @throws WouldBlockException if the channel is in non-blocking mode and the IO operation * cannot be completed immediately * @throws NeedsTaskException if the channel is not configured to run tasks automatically * and a task needs to be executed to complete the operation * @throws SSLException if the {@link SSLEngine} throws a SSLException * @throws IOException if the underlying channel throws an IOException */ long read(ByteBuffer[] dsts) throws IOException; /** * Closes the underlying channel. This method first does some form of TLS * close if not already done. The exact behavior can be configured using the * {@link TlsChannelBuilder#withWaitForCloseConfirmation}. * *

* The default behavior mimics what happens in a normal (that is, non * layered) {@link javax.net.ssl.SSLSocket#close()}. * *

* For finer control of the TLS close, use {@link #shutdown()} * * @throws IOException if the underlying channel throws an IOException during close. * Exceptions thrown during any previous TLS close are not * propagated. */ void close() throws IOException; /** *

Shuts down the TLS connection. This method emulates the behavior of OpenSSL's SSL_shutdown().

* *

The shutdown procedure consists of two steps: the sending of the "close notify" shutdown alert and the * reception of the peer's "close notify". According to the TLS standard, it is acceptable for an application to * only send its shutdown alert and then close the underlying connection without waiting for the peer's response. * When the underlying connection shall be used for more communications, the complete shutdown procedure * (bidirectional "close notify" alerts) must be performed, so that the peers stay synchronized.

* *

This class supports both uni- and bidirectional shutdown by its 2 step behavior, using this method.

* *

When this is the first party to send the "close notify" alert, this method will only send the alert, set the * {@link #shutdownSent()} flag and return false. If a unidirectional shutdown is enough, this first * call is sufficient. In order to complete the bidirectional shutdown handshake, This method must be called again. * The second call will wait for the peer's "close notify" shutdown alert. On success, the second call will return * true.

* *

If the peer already sent the "close notify" alert and it was already processed implicitly inside a read * operation, the {@link #shutdownReceived()} flag is already set. This method will then send the "close notify" * alert, set the {@link #shutdownSent()} flag and immediately return true. It is therefore recommended * to check the return value of this method and call it again, if the bidirectional shutdown is not yet * complete.

* *

If the underlying channel is blocking, this method will only return once the handshake step has been finished * or an error occurred.

* *

If the underlying channel is non-blocking, this method may throw {@link WouldBlockException} if the * underlying channel could not support the continuation of the handshake. The calling process then must repeat the * call after taking appropriate action (like waiting in a selector in case of a {@link SocketChannel}).

* *

Note that despite not being mandated by the specification, a proper TLS close is important to prevent * truncation attacks, which consists, essentially, of an adversary introducing TCP FIN segments to trick on party * to ignore the final bytes of a secure stream. For more details, see the * original paper.

* * @return whether the closing is finished. * @throws IOException if the underlying channel throws an IOException * @throws WouldBlockException if the channel is in non-blocking mode and the IO operation cannot be completed * immediately * @see TlsChannelBuilder#withWaitForCloseConfirmation(boolean) */ boolean shutdown() throws IOException; /** * Return whether this side of the connection has already received the close * notification. * * @return true if the close notification was received * @see #shutdown() */ boolean shutdownReceived(); /** * Return whether this side of the connection has already sent the close * notification. * * @return true if the close notification was sent * @see #shutdown() */ boolean shutdownSent(); }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy