/* | 
|
 * 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.AEADBadTagException;  | 
|
import javax.crypto.BadPaddingException;  | 
|
import javax.net.ssl.SSLHandshakeException;  | 
|
/** | 
|
 * Interface for SSL/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/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. | 
|
context.outputRecord.encodeV2NoCipher();  | 
|
if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {  | 
|
SSLLogger.finest("may be talking to SSLv2");  | 
|
}  | 
|
throw context.fatal(Alert.UNEXPECTED_MESSAGE, unsoe);  | 
|
} catch (AEADBadTagException bte) {  | 
|
throw context.fatal(Alert.BAD_RECORD_MAC, bte);  | 
|
} 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 != null &&  | 
|
plainText != Plaintext.PLAINTEXT_NULL &&  | 
|
                    plainText.contentType != ContentType.APPLICATION_DATA.id) { | 
|
context.dispatch(plainText);  | 
|
}  | 
|
            if (plainText == null) { | 
|
plainText = Plaintext.PLAINTEXT_NULL;  | 
|
} else if (plainText.contentType ==  | 
|
                            ContentType.APPLICATION_DATA.id) { | 
|
// check handshake status  | 
|
//  | 
|
// Note that JDK does not support 0-RTT yet. Otherwise, it is  | 
|
                // needed to check early_data. | 
|
if (!context.isNegotiated) {  | 
|
if (SSLLogger.isOn && SSLLogger.isOn("ssl,verbose")) {  | 
|
SSLLogger.warning("unexpected application data " +  | 
|
                            "before handshake completion"); | 
|
}  | 
|
throw context.fatal(Alert.UNEXPECTED_MESSAGE,  | 
|
                        "Receiving application data before handshake complete"); | 
|
}  | 
|
                // Fill the destination buffers. | 
|
if ((dsts != null) && (dstsLength > 0)) {  | 
|
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;  | 
|
}  | 
|
}  |