1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 /* 18 * Copyright 2016 The Netty Project 19 * 20 * The Netty Project licenses this file to you under the Apache License, 21 * version 2.0 (the "License"); you may not use this file except in compliance 22 * with the License. You may obtain a copy of the License at: 23 * 24 * http://www.apache.org/licenses/LICENSE-2.0 25 * 26 * Unless required by applicable law or agreed to in writing, software 27 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 28 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 29 * License for the specific language governing permissions and limitations 30 * under the License. 31 */ 32 33 package org.conscrypt; 34 35 import static java.lang.Math.min; 36 import static org.conscrypt.NativeConstants.SSL3_RT_ALERT; 37 import static org.conscrypt.NativeConstants.SSL3_RT_APPLICATION_DATA; 38 import static org.conscrypt.NativeConstants.SSL3_RT_CHANGE_CIPHER_SPEC; 39 import static org.conscrypt.NativeConstants.SSL3_RT_HANDSHAKE; 40 import static org.conscrypt.NativeConstants.SSL3_RT_HEADER_LENGTH; 41 import static org.conscrypt.NativeConstants.SSL3_RT_MAX_PACKET_SIZE; 42 43 import java.nio.ByteBuffer; 44 import javax.net.ssl.SSLException; 45 import javax.net.ssl.SSLHandshakeException; 46 47 /** 48 * Utility methods for SSL packet processing. Copied from the Netty project. 49 * <p> 50 * This is a public class to allow testing to occur on Android via CTS. 51 * 52 * @hide 53 */ 54 public final class SSLUtils { 55 static final boolean USE_ENGINE_SOCKET_BY_DEFAULT = 56 Boolean.parseBoolean(System.getProperty("org.conscrypt.useEngineSocketByDefault")); 57 static final int MAX_PROTOCOL_LENGTH = 255; 58 59 /** 60 * This is the maximum overhead when encrypting plaintext as defined by 61 * <a href="https://www.ietf.org/rfc/rfc5246.txt">rfc5264</a>, 62 * <a href="https://www.ietf.org/rfc/rfc5289.txt">rfc5289</a> and openssl implementation itself. 63 * 64 * Please note that we use a padding of 16 here as openssl uses PKC#5 which uses 16 bytes 65 * whilethe spec itself allow up to 255 bytes. 16 bytes is the max for PKC#5 (which handles it 66 * the same way as PKC#7) as we use a block size of 16. See <a 67 * href="https://tools.ietf.org/html/rfc5652#section-6.3">rfc5652#section-6.3</a>. 68 * 69 * 16 (IV) + 48 (MAC) + 1 (Padding_length field) + 15 (Padding) + 1 (ContentType) + 2 70 * (ProtocolVersion) + 2 (Length) 71 * 72 * TODO: We may need to review this calculation once TLS 1.3 becomes available. 73 */ 74 private static final int MAX_ENCRYPTION_OVERHEAD_LENGTH = 15 + 48 + 1 + 16 + 1 + 2 + 2; 75 76 private static final int MAX_ENCRYPTION_OVERHEAD_DIFF = 77 Integer.MAX_VALUE - MAX_ENCRYPTION_OVERHEAD_LENGTH; 78 79 /** 80 * Calculates the minimum bytes required in the encrypted output buffer for the given number of 81 * plaintext source bytes. 82 */ 83 public static int calculateOutNetBufSize(int pendingBytes) { 84 return min(SSL3_RT_MAX_PACKET_SIZE, 85 MAX_ENCRYPTION_OVERHEAD_LENGTH + min(MAX_ENCRYPTION_OVERHEAD_DIFF, pendingBytes)); 86 } 87 88 /** 89 * Wraps the given exception if it's not already a {@link SSLHandshakeException}. 90 */ 91 static SSLHandshakeException toSSLHandshakeException(Throwable e) { 92 if (e instanceof SSLHandshakeException) { 93 return (SSLHandshakeException) e; 94 } 95 96 return (SSLHandshakeException) new SSLHandshakeException(e.getMessage()).initCause(e); 97 } 98 99 /** 100 * Wraps the given exception if it's not already a {@link SSLException}. 101 */ 102 static SSLException toSSLException(Throwable e) { 103 if (e instanceof SSLException) { 104 return (SSLException) e; 105 } 106 return new SSLException(e); 107 } 108 109 /** 110 * Return how much bytes can be read out of the encrypted data. Be aware that this method will 111 * not 112 * increase the readerIndex of the given {@link ByteBuffer}. 113 * 114 * @param buffers The {@link ByteBuffer}s to read from. Be aware that they must have at least 115 * {@link org.conscrypt.NativeConstants#SSL3_RT_HEADER_LENGTH} bytes to read, otherwise it will 116 * throw an {@link IllegalArgumentException}. 117 * @return length The length of the encrypted packet that is included in the buffer. This will 118 * return {@code -1} if the given {@link ByteBuffer} is not encrypted at all. 119 * @throws IllegalArgumentException Is thrown if the given {@link ByteBuffer} has not at least 120 * {@link org.conscrypt.NativeConstants#SSL3_RT_HEADER_LENGTH} bytes to read. 121 */ 122 public static int getEncryptedPacketLength(ByteBuffer[] buffers, int offset) { 123 ByteBuffer buffer = buffers[offset]; 124 125 // Check if everything we need is in one ByteBuffer. If so we can make use of the fast-path. 126 if (buffer.remaining() >= SSL3_RT_HEADER_LENGTH) { 127 return getEncryptedPacketLength(buffer); 128 } 129 130 // We need to copy 5 bytes into a temporary buffer so we can parse out the packet length 131 // easily. 132 ByteBuffer tmp = ByteBuffer.allocate(SSL3_RT_HEADER_LENGTH); 133 do { 134 buffer = buffers[offset++]; 135 int pos = buffer.position(); 136 int limit = buffer.limit(); 137 if (buffer.remaining() > tmp.remaining()) { 138 buffer.limit(pos + tmp.remaining()); 139 } 140 try { 141 tmp.put(buffer); 142 } finally { 143 // Restore the original indices. 144 buffer.limit(limit); 145 buffer.position(pos); 146 } 147 } while (tmp.hasRemaining()); 148 149 // Done, flip the buffer so we can read from it. 150 tmp.flip(); 151 return getEncryptedPacketLength(tmp); 152 } 153 154 /** 155 * Encodes a list of protocols into the wire-format (length-prefixed 8-bit strings). 156 * Requires that all strings be encoded with US-ASCII. 157 * 158 * @param protocols the list of protocols to be encoded 159 * @return the encoded form of the protocol list. 160 */ 161 public static byte[] toLengthPrefixedList(String... protocols) { 162 // Calculate the encoded length. 163 int length = 0; 164 for (int i = 0; i < protocols.length; ++i) { 165 int protocolLength = protocols[i].length(); 166 167 // Verify that the length is valid here, so that we don't attempt to allocate an array 168 // below if the threshold is violated. 169 if (protocolLength == 0 || protocolLength > MAX_PROTOCOL_LENGTH) { 170 throw new IllegalArgumentException("Protocol has invalid length (" 171 + protocolLength + "): " + protocols[i]); 172 } 173 174 // Include a 1-byte prefix for each protocol. 175 length += 1 + protocolLength; 176 } 177 178 byte[] data = new byte[length]; 179 for (int dataIndex = 0, i = 0; i < protocols.length; ++i) { 180 String protocol = protocols[i]; 181 int protocolLength = protocol.length(); 182 183 // Add the length prefix. 184 data[dataIndex++] = (byte) protocolLength; 185 for (int ci = 0; ci < protocolLength; ++ci) { 186 char c = protocol.charAt(ci); 187 if (c > Byte.MAX_VALUE) { 188 // Enforce US-ASCII 189 throw new IllegalArgumentException("Protocol contains invalid character: " 190 + c + "(protocol=" + protocol + ")"); 191 } 192 data[dataIndex++] = (byte) c; 193 } 194 } 195 return data; 196 } 197 198 private static int getEncryptedPacketLength(ByteBuffer buffer) { 199 int packetLength = 0; 200 int pos = buffer.position(); 201 // SSLv3 or TLS - Check ContentType 202 switch (unsignedByte(buffer.get(pos))) { 203 case SSL3_RT_CHANGE_CIPHER_SPEC: 204 case SSL3_RT_ALERT: 205 case SSL3_RT_HANDSHAKE: 206 case SSL3_RT_APPLICATION_DATA: 207 break; 208 default: 209 // SSLv2 or bad data 210 return -1; 211 } 212 213 // SSLv3 or TLS - Check ProtocolVersion 214 int majorVersion = unsignedByte(buffer.get(pos + 1)); 215 if (majorVersion != 3) { 216 // Neither SSLv3 or TLSv1 (i.e. SSLv2 or bad data) 217 return -1; 218 } 219 220 // SSLv3 or TLS 221 packetLength = unsignedShort(buffer.getShort(pos + 3)) + SSL3_RT_HEADER_LENGTH; 222 if (packetLength <= SSL3_RT_HEADER_LENGTH) { 223 // Neither SSLv3 or TLSv1 (i.e. SSLv2 or bad data) 224 return -1; 225 } 226 return packetLength; 227 } 228 229 private static short unsignedByte(byte b) { 230 return (short) (b & 0xFF); 231 } 232 233 private static int unsignedShort(short s) { 234 return s & 0xFFFF; 235 } 236 237 private SSLUtils() {} 238 } 239