Home | History | Annotate | Download | only in conscrypt
      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