1 /* 2 * Copyright (c) 2018, 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.AEADBadTagException; 32 import javax.crypto.BadPaddingException; 33 import javax.net.ssl.SSLHandshakeException; 34 35 /** 36 * Interface for SSL/TLS transportation. 37 */ 38 interface SSLTransport { 39 40 /** 41 * Returns the host name of the peer. 42 * 43 * @return the host name of the peer, or null if nothing is 44 * available. 45 */ 46 String getPeerHost(); 47 48 /** 49 * Returns the port number of the peer. 50 * 51 * @return the port number of the peer, or -1 if nothing is 52 * available. 53 */ 54 int getPeerPort(); 55 56 /** 57 * Shutdown the transport. 58 */ 59 default void shutdown() throws IOException { 60 // blank 61 } 62 63 /** 64 * Return true if delegated tasks used for handshaking operations. 65 * 66 * @return true if delegated tasks used for handshaking operations. 67 */ 68 boolean useDelegatedTask(); 69 70 /** 71 * Decodes an array of SSL/TLS network source data into the 72 * destination application data buffers. 73 * 74 * For SSL/TLS connections, if no source data, the network data may be 75 * received from the underlying underlying SSL/TLS input stream. 76 * 77 * @param context the transportation context 78 * @param srcs an array of {@code ByteBuffers} containing the 79 * inbound network data 80 * @param srcsOffset The offset within the {@code srcs} buffer array 81 * of the first buffer from which bytes are to be 82 * retrieved; it must be non-negative and no larger 83 * than {@code srcs.length}. 84 * @param srcsLength The maximum number of {@code srcs} buffers to be 85 * accessed; it must be non-negative and no larger than 86 * {@code srcs.length} - {@code srcsOffset}. 87 * @param dsts an array of {@code ByteBuffers} to hold inbound 88 * application data 89 * @param dstsOffset The offset within the {@code dsts} buffer array 90 * of the first buffer from which bytes are to be 91 * placed; it must be non-negative and no larger 92 * than {@code dsts.length}. 93 * @param dstsLength The maximum number of {@code dsts} buffers to be 94 * accessed; it must be non-negative and no larger than 95 * {@code dsts.length} - {@code dstsOffset}. 96 * 97 * @return a {@code Plaintext} describing the result of 98 * the operation 99 * @throws IOException if a problem was encountered while receiving or 100 * decoding networking data 101 */ 102 static Plaintext decode(TransportContext context, 103 ByteBuffer[] srcs, int srcsOffset, int srcsLength, 104 ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws IOException { 105 106 Plaintext[] plaintexts = null; 107 try { 108 plaintexts = 109 context.inputRecord.decode(srcs, srcsOffset, srcsLength); 110 } catch (UnsupportedOperationException unsoe) { // SSLv2Hello 111 // Hack code to deliver SSLv2 error message for SSL/TLS connections. 112 context.outputRecord.encodeV2NoCipher(); 113 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { 114 SSLLogger.finest("may be talking to SSLv2"); 115 } 116 117 throw context.fatal(Alert.UNEXPECTED_MESSAGE, unsoe); 118 } catch (AEADBadTagException bte) { 119 throw context.fatal(Alert.BAD_RECORD_MAC, bte); 120 } catch (BadPaddingException bpe) { 121 /* 122 * The basic SSLv3 record protection involves (optional) 123 * encryption for privacy, and an integrity check ensuring 124 * data origin authentication. We do them both here, and 125 * throw a fatal alert if the integrity check fails. 126 */ 127 Alert alert = (context.handshakeContext != null) ? 128 Alert.HANDSHAKE_FAILURE : 129 Alert.BAD_RECORD_MAC; 130 throw context.fatal(alert, bpe); 131 } catch (SSLHandshakeException she) { 132 // may be record sequence number overflow 133 throw context.fatal(Alert.HANDSHAKE_FAILURE, she); 134 } catch (EOFException eofe) { 135 // rethrow EOFException, the call will handle it if neede. 136 throw eofe; 137 } catch (IOException ioe) { 138 throw context.fatal(Alert.UNEXPECTED_MESSAGE, ioe); 139 } 140 141 if (plaintexts == null || plaintexts.length == 0) { 142 // Connection closed or record should be discarded. 143 return Plaintext.PLAINTEXT_NULL; 144 } 145 146 Plaintext finalPlaintext = Plaintext.PLAINTEXT_NULL; 147 for (Plaintext plainText : plaintexts) { 148 // plainText should never be null for TLS protocols 149 if (plainText != null && 150 plainText != Plaintext.PLAINTEXT_NULL && 151 plainText.contentType != ContentType.APPLICATION_DATA.id) { 152 context.dispatch(plainText); 153 } 154 155 if (plainText == null) { 156 plainText = Plaintext.PLAINTEXT_NULL; 157 } else if (plainText.contentType == 158 ContentType.APPLICATION_DATA.id) { 159 // check handshake status 160 // 161 // Note that JDK does not support 0-RTT yet. Otherwise, it is 162 // needed to check early_data. 163 if (!context.isNegotiated) { 164 if (SSLLogger.isOn && SSLLogger.isOn("ssl,verbose")) { 165 SSLLogger.warning("unexpected application data " + 166 "before handshake completion"); 167 } 168 169 throw context.fatal(Alert.UNEXPECTED_MESSAGE, 170 "Receiving application data before handshake complete"); 171 } 172 173 // Fill the destination buffers. 174 if ((dsts != null) && (dstsLength > 0)) { 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 }