Home | History | Annotate | Download | only in conscrypt
      1 /*
      2  * Copyright (C) 2017 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 package org.conscrypt;
     18 
     19 import static org.conscrypt.Preconditions.checkNotNull;
     20 
     21 import java.util.Arrays;
     22 import java.util.List;
     23 import javax.net.ssl.SSLEngine;
     24 import javax.net.ssl.SSLSocket;
     25 
     26 /**
     27  * An adapter to bridge between the native code and the {@link ApplicationProtocolSelector} API.
     28  */
     29 final class ApplicationProtocolSelectorAdapter {
     30     private static final int NO_PROTOCOL_SELECTED = -1;
     31 
     32     private final SSLEngine engine;
     33     private final SSLSocket socket;
     34     private final ApplicationProtocolSelector selector;
     35 
     36     ApplicationProtocolSelectorAdapter(SSLEngine engine, ApplicationProtocolSelector selector) {
     37         this.engine = checkNotNull(engine, "engine");
     38         this.socket = null;
     39         this.selector = checkNotNull(selector, "selector");
     40     }
     41 
     42     ApplicationProtocolSelectorAdapter(SSLSocket socket, ApplicationProtocolSelector selector) {
     43         this.engine = null;
     44         this.socket = checkNotNull(socket, "socket");
     45         this.selector = checkNotNull(selector, "selector");
     46     }
     47 
     48     /**
     49      * Performs the ALPN protocol selection from the given list of length-delimited peer protocols.
     50      * @param encodedProtocols the peer protocols in length-delimited form.
     51      * @return If successful, returns the offset into the {@code lenghPrefixedList} array of the
     52      * selected protocol (i.e. points to the length prefix). Otherwise, returns
     53      * {@link #NO_PROTOCOL_SELECTED}.
     54      */
     55     int selectApplicationProtocol(byte[] encodedProtocols) {
     56         if (encodedProtocols == null || encodedProtocols.length == 0) {
     57             return NO_PROTOCOL_SELECTED;
     58         }
     59 
     60         // Decode the protocols.
     61         List<String> protocols = Arrays.asList(SSLUtils.decodeProtocols(encodedProtocols));
     62 
     63         // Select the protocol.
     64         final String selected;
     65         if (engine != null ) {
     66             selected = selector.selectApplicationProtocol(engine, protocols);
     67         } else {
     68             selected = selector.selectApplicationProtocol(socket, protocols);
     69         }
     70         if (selected == null || selected.isEmpty()) {
     71             return NO_PROTOCOL_SELECTED;
     72         }
     73 
     74         int offset = 0;
     75         for (String protocol : protocols) {
     76             if (selected.equals(protocol)) {
     77                 // Found the selected protocol. Return the index position of the beginning of
     78                 // the protocol.
     79                 return offset;
     80             }
     81 
     82             // Add 1 byte for the length prefix.
     83             offset += 1 + protocol.length();
     84         }
     85 
     86         return NO_PROTOCOL_SELECTED;
     87     }
     88 }
     89