• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 Square, Inc.
3  * Copyright (C) 2012 The Android Open Source Project
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 package com.squareup.okhttp.internal;
18 
19 import dalvik.system.SocketTagger;
20 import java.io.IOException;
21 import java.io.OutputStream;
22 import java.net.InetSocketAddress;
23 import java.net.Socket;
24 import java.net.SocketException;
25 import java.net.URI;
26 import java.net.URISyntaxException;
27 import java.net.URL;
28 import java.util.List;
29 import java.util.zip.Deflater;
30 import java.util.zip.DeflaterOutputStream;
31 import javax.net.ssl.SSLSocket;
32 
33 import com.android.org.conscrypt.OpenSSLSocketImpl;
34 import com.squareup.okhttp.Protocol;
35 import okio.ByteString;
36 
37 /**
38  * Access to proprietary Android APIs. Doesn't use reflection.
39  */
40 public final class Platform {
41     private static final Platform PLATFORM = new Platform();
42 
get()43     public static Platform get() {
44         return PLATFORM;
45     }
46 
logW(String warning)47     public void logW(String warning) {
48         System.logW(warning);
49     }
50 
tagSocket(Socket socket)51     public void tagSocket(Socket socket) throws SocketException {
52         SocketTagger.get().tag(socket);
53     }
54 
untagSocket(Socket socket)55     public void untagSocket(Socket socket) throws SocketException {
56         SocketTagger.get().untag(socket);
57     }
58 
toUriLenient(URL url)59     public URI toUriLenient(URL url) throws URISyntaxException {
60         return url.toURILenient();
61     }
62 
enableTlsExtensions(SSLSocket socket, String uriHost)63     public void enableTlsExtensions(SSLSocket socket, String uriHost) {
64         if (socket instanceof OpenSSLSocketImpl) {
65             OpenSSLSocketImpl openSSLSocket = (OpenSSLSocketImpl) socket;
66             openSSLSocket.setUseSessionTickets(true);
67             openSSLSocket.setHostname(uriHost);
68         }
69     }
70 
supportTlsIntolerantServer(SSLSocket socket)71     public void supportTlsIntolerantServer(SSLSocket socket) {
72         // In accordance with https://tools.ietf.org/html/draft-ietf-tls-downgrade-scsv-00
73         // the SCSV cipher is added to signal that a protocol fallback has taken place.
74         final String fallbackScsv = "TLS_FALLBACK_SCSV";
75         boolean socketSupportsFallbackScsv = false;
76         String[] supportedCipherSuites = socket.getSupportedCipherSuites();
77         for (int i = supportedCipherSuites.length - 1; i >= 0; i--) {
78             String supportedCipherSuite = supportedCipherSuites[i];
79             if (fallbackScsv.equals(supportedCipherSuite)) {
80                 socketSupportsFallbackScsv = true;
81                 break;
82             }
83         }
84         if (socketSupportsFallbackScsv) {
85             // Add the SCSV cipher to the set of enabled ciphers.
86             String[] enabledCipherSuites = socket.getEnabledCipherSuites();
87             String[] newEnabledCipherSuites = new String[enabledCipherSuites.length + 1];
88             System.arraycopy(enabledCipherSuites, 0,
89                     newEnabledCipherSuites, 0, enabledCipherSuites.length);
90             newEnabledCipherSuites[newEnabledCipherSuites.length - 1] = fallbackScsv;
91             socket.setEnabledCipherSuites(newEnabledCipherSuites);
92         }
93         socket.setEnabledProtocols(new String[]{"SSLv3"});
94     }
95 
96     /**
97      * Returns the negotiated protocol, or null if no protocol was negotiated.
98      */
getNpnSelectedProtocol(SSLSocket socket)99     public ByteString getNpnSelectedProtocol(SSLSocket socket) {
100         if (!(socket instanceof OpenSSLSocketImpl)) {
101             return null;
102         }
103 
104         OpenSSLSocketImpl socketImpl = (OpenSSLSocketImpl) socket;
105         // Prefer ALPN's result if it is present.
106         byte[] alpnResult = socketImpl.getAlpnSelectedProtocol();
107         if (alpnResult != null) {
108             return ByteString.of(alpnResult);
109         }
110         byte[] npnResult = socketImpl.getNpnSelectedProtocol();
111         return npnResult == null ? null : ByteString.of(npnResult);
112     }
113 
114     /**
115      * Sets client-supported protocols on a socket to send to a server. The
116      * protocols are only sent if the socket implementation supports NPN.
117      */
setNpnProtocols(SSLSocket socket, List<Protocol> npnProtocols)118     public void setNpnProtocols(SSLSocket socket, List<Protocol> npnProtocols) {
119         if (socket instanceof OpenSSLSocketImpl) {
120             OpenSSLSocketImpl socketImpl = (OpenSSLSocketImpl) socket;
121             byte[] protocols = concatLengthPrefixed(npnProtocols);
122             socketImpl.setAlpnProtocols(protocols);
123             socketImpl.setNpnProtocols(protocols);
124         }
125     }
126 
127     /**
128      * Returns a deflater output stream that supports SYNC_FLUSH for SPDY name
129      * value blocks. This throws an {@link UnsupportedOperationException} on
130      * Java 6 and earlier where there is no built-in API to do SYNC_FLUSH.
131      */
newDeflaterOutputStream( OutputStream out, Deflater deflater, boolean syncFlush)132     public OutputStream newDeflaterOutputStream(
133             OutputStream out, Deflater deflater, boolean syncFlush) {
134         return new DeflaterOutputStream(out, deflater, syncFlush);
135     }
136 
connectSocket(Socket socket, InetSocketAddress address, int connectTimeout)137     public void connectSocket(Socket socket, InetSocketAddress address,
138               int connectTimeout) throws IOException {
139         socket.connect(address, connectTimeout);
140     }
141 
142     /** Prefix used on custom headers. */
getPrefix()143     public String getPrefix() {
144         return "X-Android";
145     }
146 
147     /**
148      * Concatenation of 8-bit, length prefixed protocol names.
149      *
150      * http://tools.ietf.org/html/draft-agl-tls-nextprotoneg-04#page-4
151      */
concatLengthPrefixed(List<Protocol> protocols)152     static byte[] concatLengthPrefixed(List<Protocol> protocols) {
153         int size = 0;
154         for (Protocol protocol : protocols) {
155             size += protocol.name.size() + 1; // add a byte for 8-bit length prefix.
156         }
157         byte[] result = new byte[size];
158         int pos = 0;
159         for (Protocol protocol : protocols) {
160             int nameSize = protocol.name.size();
161             result[pos++] = (byte) nameSize;
162             // toByteArray allocates an array, but this is only called on new connections.
163             System.arraycopy(protocol.name.toByteArray(), 0, result, pos, nameSize);
164             pos += nameSize;
165         }
166         return result;
167     }
168 }
169