mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-29 20:48:29 +00:00
206 lines
8.3 KiB
Java
206 lines
8.3 KiB
Java
/*
|
|
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation. Oracle designates this
|
|
* particular file as subject to the "Classpath" exception as provided
|
|
* by Oracle in the LICENSE file that accompanied this code.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*/
|
|
|
|
package sun.security.ssl;
|
|
|
|
import java.io.EOFException;
|
|
import java.io.IOException;
|
|
import java.nio.ByteBuffer;
|
|
import javax.crypto.BadPaddingException;
|
|
import javax.net.ssl.SSLHandshakeException;
|
|
|
|
/**
|
|
* Interface for SSL/(D)TLS transportation.
|
|
*/
|
|
interface SSLTransport {
|
|
|
|
/**
|
|
* Returns the host name of the peer.
|
|
*
|
|
* @return the host name of the peer, or null if nothing is
|
|
* available.
|
|
*/
|
|
String getPeerHost();
|
|
|
|
/**
|
|
* Returns the port number of the peer.
|
|
*
|
|
* @return the port number of the peer, or -1 if nothing is
|
|
* available.
|
|
*/
|
|
int getPeerPort();
|
|
|
|
/**
|
|
* Shutdown the transport.
|
|
*/
|
|
default void shutdown() throws IOException {
|
|
// blank
|
|
}
|
|
|
|
/**
|
|
* Return true if delegated tasks used for handshaking operations.
|
|
*
|
|
* @return true if delegated tasks used for handshaking operations.
|
|
*/
|
|
boolean useDelegatedTask();
|
|
|
|
/**
|
|
* Decodes an array of SSL/(D)TLS network source data into the
|
|
* destination application data buffers.
|
|
*
|
|
* For SSL/TLS connections, if no source data, the network data may be
|
|
* received from the underlying underlying SSL/TLS input stream.
|
|
*
|
|
* @param context the transportation context
|
|
* @param srcs an array of {@code ByteBuffers} containing the
|
|
* inbound network data
|
|
* @param srcsOffset The offset within the {@code srcs} buffer array
|
|
* of the first buffer from which bytes are to be
|
|
* retrieved; it must be non-negative and no larger
|
|
* than {@code srcs.length}.
|
|
* @param srcsLength The maximum number of {@code srcs} buffers to be
|
|
* accessed; it must be non-negative and no larger than
|
|
* {@code srcs.length} - {@code srcsOffset}.
|
|
* @param dsts an array of {@code ByteBuffers} to hold inbound
|
|
* application data
|
|
* @param dstsOffset The offset within the {@code dsts} buffer array
|
|
* of the first buffer from which bytes are to be
|
|
* placed; it must be non-negative and no larger
|
|
* than {@code dsts.length}.
|
|
* @param dstsLength The maximum number of {@code dsts} buffers to be
|
|
* accessed; it must be non-negative and no larger than
|
|
* {@code dsts.length} - {@code dstsOffset}.
|
|
*
|
|
* @return a {@code Plaintext} describing the result of
|
|
* the operation
|
|
* @throws IOException if a problem was encountered while receiving or
|
|
* decoding networking data
|
|
*/
|
|
static Plaintext decode(TransportContext context,
|
|
ByteBuffer[] srcs, int srcsOffset, int srcsLength,
|
|
ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws IOException {
|
|
|
|
Plaintext[] plaintexts = null;
|
|
try {
|
|
plaintexts =
|
|
context.inputRecord.decode(srcs, srcsOffset, srcsLength);
|
|
} catch (UnsupportedOperationException unsoe) { // SSLv2Hello
|
|
// Hack code to deliver SSLv2 error message for SSL/TLS connections.
|
|
if (!context.sslContext.isDTLS()) {
|
|
context.outputRecord.encodeV2NoCipher();
|
|
if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
|
|
SSLLogger.finest("may be talking to SSLv2");
|
|
}
|
|
}
|
|
|
|
throw context.fatal(Alert.UNEXPECTED_MESSAGE, unsoe);
|
|
} catch (BadPaddingException bpe) {
|
|
/*
|
|
* The basic SSLv3 record protection involves (optional)
|
|
* encryption for privacy, and an integrity check ensuring
|
|
* data origin authentication. We do them both here, and
|
|
* throw a fatal alert if the integrity check fails.
|
|
*/
|
|
Alert alert = (context.handshakeContext != null) ?
|
|
Alert.HANDSHAKE_FAILURE :
|
|
Alert.BAD_RECORD_MAC;
|
|
throw context.fatal(alert, bpe);
|
|
} catch (SSLHandshakeException she) {
|
|
// may be record sequence number overflow
|
|
throw context.fatal(Alert.HANDSHAKE_FAILURE, she);
|
|
} catch (EOFException eofe) {
|
|
// rethrow EOFException, the call will handle it if neede.
|
|
throw eofe;
|
|
} catch (IOException ioe) {
|
|
throw context.fatal(Alert.UNEXPECTED_MESSAGE, ioe);
|
|
}
|
|
|
|
if (plaintexts == null || plaintexts.length == 0) {
|
|
// Connection closed or record should be discarded.
|
|
return Plaintext.PLAINTEXT_NULL;
|
|
}
|
|
|
|
Plaintext finalPlaintext = Plaintext.PLAINTEXT_NULL;
|
|
for (Plaintext plainText : plaintexts) {
|
|
// plainText should never be null for TLS protocols
|
|
if (plainText == Plaintext.PLAINTEXT_NULL) {
|
|
// Only happens for DTLS protocols.
|
|
//
|
|
// Received a retransmitted flight, and need to retransmit the
|
|
// previous delivered handshake flight messages.
|
|
if (context.handshakeContext != null &&
|
|
context.handshakeContext.sslConfig.enableRetransmissions &&
|
|
context.sslContext.isDTLS()) {
|
|
if (SSLLogger.isOn && SSLLogger.isOn("ssl,verbose")) {
|
|
SSLLogger.finest("retransmited handshake flight");
|
|
}
|
|
|
|
context.outputRecord.launchRetransmission();
|
|
} // Otherwise, discard the retransmitted flight.
|
|
} else if (plainText != null &&
|
|
plainText.contentType != ContentType.APPLICATION_DATA.id) {
|
|
context.dispatch(plainText);
|
|
}
|
|
|
|
if (plainText == null) {
|
|
plainText = Plaintext.PLAINTEXT_NULL;
|
|
} else {
|
|
// Fill the destination buffers.
|
|
if ((dsts != null) && (dstsLength > 0) &&
|
|
(plainText.contentType ==
|
|
ContentType.APPLICATION_DATA.id)) {
|
|
|
|
ByteBuffer fragment = plainText.fragment;
|
|
int remains = fragment.remaining();
|
|
|
|
// Should have enough room in the destination buffers.
|
|
int limit = dstsOffset + dstsLength;
|
|
for (int i = dstsOffset;
|
|
((i < limit) && (remains > 0)); i++) {
|
|
|
|
int amount = Math.min(dsts[i].remaining(), remains);
|
|
fragment.limit(fragment.position() + amount);
|
|
dsts[i].put(fragment);
|
|
remains -= amount;
|
|
|
|
if (!dsts[i].hasRemaining()) {
|
|
dstsOffset++;
|
|
}
|
|
}
|
|
|
|
if (remains > 0) {
|
|
throw context.fatal(Alert.INTERNAL_ERROR,
|
|
"no sufficient room in the destination buffers");
|
|
}
|
|
}
|
|
}
|
|
|
|
finalPlaintext = plainText;
|
|
}
|
|
|
|
return finalPlaintext;
|
|
}
|
|
}
|