Platform.java revision b860016f415dfc5655dcee45f70e8871a2e3edfe
1/* 2 * Copyright 2014 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 17package org.conscrypt; 18 19import android.os.Build; 20import android.util.Log; 21import java.io.FileDescriptor; 22import java.lang.reflect.Field; 23import java.lang.reflect.Method; 24import java.net.Socket; 25import java.security.InvalidKeyException; 26import java.security.PrivateKey; 27import java.security.cert.CertificateException; 28import java.security.cert.X509Certificate; 29import java.security.spec.ECParameterSpec; 30 31import javax.net.ssl.SSLEngine; 32import javax.net.ssl.SSLParameters; 33import javax.net.ssl.X509TrustManager; 34 35/** 36 * 37 */ 38public class Platform { 39 private static final String TAG = "Conscrypt"; 40 41 private static Method m_getCurveName; 42 static { 43 try { 44 m_getCurveName = ECParameterSpec.class.getDeclaredMethod("getCurveName"); 45 m_getCurveName.setAccessible(true); 46 } catch (Exception ignored) { 47 } 48 } 49 50 public static void setup() { 51 } 52 53 public static FileDescriptor getFileDescriptor(Socket s) { 54 try { 55 Field f_impl = Socket.class.getDeclaredField("impl"); 56 f_impl.setAccessible(true); 57 Object socketImpl = f_impl.get(s); 58 Class<?> c_socketImpl = Class.forName("java.net.SocketImpl"); 59 Field f_fd = c_socketImpl.getDeclaredField("fd"); 60 f_fd.setAccessible(true); 61 return (FileDescriptor) f_fd.get(socketImpl); 62 } catch (Exception e) { 63 throw new RuntimeException("Can't get FileDescriptor from socket", e); 64 } 65 } 66 67 public static FileDescriptor getFileDescriptorFromSSLSocket(OpenSSLSocketImpl openSSLSocketImpl) { 68 return getFileDescriptor(openSSLSocketImpl); 69 } 70 71 public static String getCurveName(ECParameterSpec spec) { 72 if (m_getCurveName == null) { 73 return null; 74 } 75 try { 76 return (String) m_getCurveName.invoke(spec); 77 } catch (Exception e) { 78 return null; 79 } 80 } 81 82 public static void setCurveName(ECParameterSpec spec, String curveName) { 83 try { 84 Method setCurveName = spec.getClass().getDeclaredMethod("setCurveName", String.class); 85 setCurveName.invoke(spec, curveName); 86 } catch (Exception ignored) { 87 } 88 } 89 90 public static void setSocketTimeout(Socket s, long timeoutMillis) { 91 // TODO: implement this for unbundled 92 } 93 94 public static void setEndpointIdentificationAlgorithm(SSLParameters params, 95 String endpointIdentificationAlgorithm) { 96 // TODO: implement this for unbundled 97 } 98 99 public static String getEndpointIdentificationAlgorithm(SSLParameters params) { 100 // TODO: implement this for unbundled 101 return null; 102 } 103 104 public static void checkServerTrusted(X509TrustManager x509tm, X509Certificate[] chain, 105 String authType, String host) throws CertificateException { 106 // TODO: use reflection to find whether we have TrustManagerImpl 107 /* 108 if (x509tm instanceof TrustManagerImpl) { 109 TrustManagerImpl tm = (TrustManagerImpl) x509tm; 110 tm.checkServerTrusted(chain, authType, host); 111 } else { 112 */ 113 x509tm.checkServerTrusted(chain, authType); 114 /* 115 } 116 */ 117 } 118 119 /** 120 * Wraps an old AndroidOpenSSL key instance. This is not needed on platform 121 * builds since we didn't backport, so return null. This code is from 122 * Chromium's net/android/java/src/org/chromium/net/DefaultAndroidKeyStore.java 123 */ 124 public static OpenSSLKey wrapRsaKey(PrivateKey javaKey) throws InvalidKeyException { 125 // This fixup only applies to pre-JB-MR1 126 if (Build.VERSION.SDK_INT >= 17) { 127 return null; 128 } 129 130 // First, check that this is a proper instance of OpenSSLRSAPrivateKey 131 // or one of its sub-classes. 132 Class<?> superClass; 133 try { 134 superClass = Class 135 .forName("org.apache.harmony.xnet.provider.jsse.OpenSSLRSAPrivateKey"); 136 } catch (Exception e) { 137 // This may happen if the target device has a completely different 138 // implementation of the java.security APIs, compared to vanilla 139 // Android. Highly unlikely, but still possible. 140 Log.e(TAG, "Cannot find system OpenSSLRSAPrivateKey class: " + e); 141 return null; 142 } 143 if (!superClass.isInstance(javaKey)) { 144 // This may happen if the PrivateKey was not created by the 145 // "AndroidOpenSSL" 146 // provider, which should be the default. That could happen if an 147 // OEM decided 148 // to implement a different default provider. Also highly unlikely. 149 Log.e(TAG, "Private key is not an OpenSSLRSAPrivateKey instance, its class name is:" 150 + javaKey.getClass().getCanonicalName()); 151 return null; 152 } 153 154 try { 155 // Use reflection to invoke the 'getOpenSSLKey()' method on 156 // the private key. This returns another Java object that wraps 157 // a native EVP_PKEY. Note that the method is final, so calling 158 // the superclass implementation is ok. 159 Method getKey = superClass.getDeclaredMethod("getOpenSSLKey"); 160 getKey.setAccessible(true); 161 Object opensslKey = null; 162 try { 163 opensslKey = getKey.invoke(javaKey); 164 } finally { 165 getKey.setAccessible(false); 166 } 167 if (opensslKey == null) { 168 // Bail when detecting OEM "enhancement". 169 Log.e(TAG, "Could not getOpenSSLKey on instance: " + javaKey.toString()); 170 return null; 171 } 172 173 // Use reflection to invoke the 'getPkeyContext' method on the 174 // result of the getOpenSSLKey(). This is an 32-bit integer 175 // which is the address of an EVP_PKEY object. Note that this 176 // method these days returns a 64-bit long, but since this code 177 // path is used for older Android versions, it may still return 178 // a 32-bit int here. To be on the safe side, we cast the return 179 // value via Number rather than directly to Integer or Long. 180 Method getPkeyContext; 181 try { 182 getPkeyContext = opensslKey.getClass().getDeclaredMethod("getPkeyContext"); 183 } catch (Exception e) { 184 // Bail here too, something really not working as expected. 185 Log.e(TAG, "No getPkeyContext() method on OpenSSLKey member:" + e); 186 return null; 187 } 188 getPkeyContext.setAccessible(true); 189 long evp_pkey = 0; 190 try { 191 evp_pkey = ((Number) getPkeyContext.invoke(opensslKey)).longValue(); 192 } finally { 193 getPkeyContext.setAccessible(false); 194 } 195 if (evp_pkey == 0) { 196 // The PrivateKey is probably rotten for some reason. 197 Log.e(TAG, "getPkeyContext() returned null"); 198 return null; 199 } 200 return new OpenSSLKey(evp_pkey); 201 } catch (Exception e) { 202 Log.e(TAG, "Error during conversion of privatekey instance: " + javaKey.toString(), e); 203 return null; 204 } 205 } 206} 207