1 /* 2 * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.security.ssl; 27 28 import java.io.EOFException; 29 import java.io.IOException; 30 import java.nio.ByteBuffer; 31 import javax.crypto.BadPaddingException; 32 import javax.net.ssl.SSLHandshakeException; 33 34 /** 35 * Interface for SSL/(D)TLS transportation. 36 */ 37 interface SSLTransport { 38 39 /** 40 * Returns the host name of the peer. 41 * 42 * @return the host name of the peer, or null if nothing is 43 * available. 44 */ 45 String getPeerHost(); 46 47 /** 48 * Returns the port number of the peer. 49 * 50 * @return the port number of the peer, or -1 if nothing is 51 * available. 52 */ 53 int getPeerPort(); 54 55 /** 56 * Shutdown the transport. 57 */ 58 default void shutdown() throws IOException { 59 // blank 60 } 61 62 /** 63 * Return true if delegated tasks used for handshaking operations. 64 * 65 * @return true if delegated tasks used for handshaking operations. 66 */ 67 boolean useDelegatedTask(); 68 69 /** 70 * Decodes an array of SSL/(D)TLS network source data into the 71 * destination application data buffers. 72 * 73 * For SSL/TLS connections, if no source data, the network data may be 74 * received from the underlying SSL/TLS input stream. 75 * 76 * @param context the transportation context 77 * @param srcs an array of {@code ByteBuffers} containing the 78 * inbound network data 79 * @param srcsOffset The offset within the {@code srcs} buffer array 80 * of the first buffer from which bytes are to be 81 * retrieved; it must be non-negative and no larger 82 * than {@code srcs.length}. 83 * @param srcsLength The maximum number of {@code srcs} buffers to be 84 * accessed; it must be non-negative and no larger than 85 * {@code srcs.length} - {@code srcsOffset}. 86 * @param dsts an array of {@code ByteBuffers} to hold inbound 87 * application data 88 * @param dstsOffset The offset within the {@code dsts} buffer array 89 * of the first buffer from which bytes are to be 90 * placed; it must be non-negative and no larger 91 * than {@code dsts.length}. 92 * @param dstsLength The maximum number of {@code dsts} buffers to be 93 * accessed; it must be non-negative and no larger than 94 * {@code dsts.length} - {@code dstsOffset}. 95 * 96 * @return a {@code Plaintext} describing the result of 97 * the operation 98 * @throws IOException if a problem was encountered while receiving or 99 * decoding networking data 100 */ 101 static Plaintext decode(TransportContext context, 102 ByteBuffer[] srcs, int srcsOffset, int srcsLength, 103 ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws IOException { 104 105 Plaintext[] plaintexts = null; 106 try { 107 plaintexts = 108 context.inputRecord.decode(srcs, srcsOffset, srcsLength); 109 } catch (UnsupportedOperationException unsoe) { // SSLv2Hello 110 // Hack code to deliver SSLv2 error message for SSL/TLS connections. 111 if (!context.sslContext.isDTLS()) { 112 context.outputRecord.encodeV2NoCipher(); 113 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { 114 SSLLogger.finest("may be talking to SSLv2"); 115 } 116 } 117 118 throw context.fatal(Alert.UNEXPECTED_MESSAGE, unsoe); 119 } catch (BadPaddingException bpe) { 120 /* 121 * The basic SSLv3 record protection involves (optional) 122 * encryption for privacy, and an integrity check ensuring 123 * data origin authentication. We do them both here, and 124 * throw a fatal alert if the integrity check fails. 125 */ 126 Alert alert = (context.handshakeContext != null) ? 127 Alert.HANDSHAKE_FAILURE : 128 Alert.BAD_RECORD_MAC; 129 throw context.fatal(alert, bpe); 130 } catch (SSLHandshakeException she) { 131 // may be record sequence number overflow 132 throw context.fatal(Alert.HANDSHAKE_FAILURE, she); 133 } catch (EOFException eofe) { 134 // rethrow EOFException, the call will handle it if neede. 135 throw eofe; 136 } catch (IOException ioe) { 137 throw context.fatal(Alert.UNEXPECTED_MESSAGE, ioe); 138 } 139 140 if (plaintexts == null || plaintexts.length == 0) { 141 // Connection closed or record should be discarded. 142 return Plaintext.PLAINTEXT_NULL; 143 } 144 145 Plaintext finalPlaintext = Plaintext.PLAINTEXT_NULL; 146 for (Plaintext plainText : plaintexts) { 147 // plainText should never be null for TLS protocols 148 if (plainText == Plaintext.PLAINTEXT_NULL) { 149 // Only happens for DTLS protocols. 150 // 151 // Received a retransmitted flight, and need to retransmit the 152 // previous delivered handshake flight messages. 153 if (context.handshakeContext != null && 154 context.handshakeContext.sslConfig.enableRetransmissions && 155 context.sslContext.isDTLS()) { 156 if (SSLLogger.isOn && SSLLogger.isOn("ssl,verbose")) { 157 SSLLogger.finest("retransmited handshake flight"); 158 } 159 160 context.outputRecord.launchRetransmission(); 161 } // Otherwise, discard the retransmitted flight. 162 } else if (plainText != null && 163 plainText.contentType != ContentType.APPLICATION_DATA.id) { 164 context.dispatch(plainText); 165 } 166 167 if (plainText == null) { 168 plainText = Plaintext.PLAINTEXT_NULL; 169 } else { 170 // Fill the destination buffers. 171 if ((dsts != null) && (dstsLength > 0) && 172 (plainText.contentType == 173 ContentType.APPLICATION_DATA.id)) { 174 175 ByteBuffer fragment = plainText.fragment; 176 int remains = fragment.remaining(); 177 178 // Should have enough room in the destination buffers. 179 int limit = dstsOffset + dstsLength; 180 for (int i = dstsOffset; 181 ((i < limit) && (remains > 0)); i++) { 182 183 int amount = Math.min(dsts[i].remaining(), remains); 184 fragment.limit(fragment.position() + amount); 185 dsts[i].put(fragment); 186 remains -= amount; 187 188 if (!dsts[i].hasRemaining()) { 189 dstsOffset++; 190 } 191 } 192 193 if (remains > 0) { 194 throw context.fatal(Alert.INTERNAL_ERROR, 195 "no sufficient room in the destination buffers"); 196 } 197 } 198 } 199 200 finalPlaintext = plainText; 201 } 202 203 return finalPlaintext; 204 } 205 }