1c5912e4920bb4fa1979d63d47e7f430e87e3820fMakoto Onuki/* 2c5912e4920bb4fa1979d63d47e7f430e87e3820fMakoto Onuki * Copyright (C) 2010 The Android Open Source Project 3c5912e4920bb4fa1979d63d47e7f430e87e3820fMakoto Onuki * 4c5912e4920bb4fa1979d63d47e7f430e87e3820fMakoto Onuki * Licensed under the Apache License, Version 2.0 (the "License"); 5c5912e4920bb4fa1979d63d47e7f430e87e3820fMakoto Onuki * you may not use this file except in compliance with the License. 6c5912e4920bb4fa1979d63d47e7f430e87e3820fMakoto Onuki * You may obtain a copy of the License at 7c5912e4920bb4fa1979d63d47e7f430e87e3820fMakoto Onuki * 8c5912e4920bb4fa1979d63d47e7f430e87e3820fMakoto Onuki * http://www.apache.org/licenses/LICENSE-2.0 9c5912e4920bb4fa1979d63d47e7f430e87e3820fMakoto Onuki * 10c5912e4920bb4fa1979d63d47e7f430e87e3820fMakoto Onuki * Unless required by applicable law or agreed to in writing, software 11c5912e4920bb4fa1979d63d47e7f430e87e3820fMakoto Onuki * distributed under the License is distributed on an "AS IS" BASIS, 12c5912e4920bb4fa1979d63d47e7f430e87e3820fMakoto Onuki * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c5912e4920bb4fa1979d63d47e7f430e87e3820fMakoto Onuki * See the License for the specific language governing permissions and 14c5912e4920bb4fa1979d63d47e7f430e87e3820fMakoto Onuki * limitations under the License. 15c5912e4920bb4fa1979d63d47e7f430e87e3820fMakoto Onuki */ 16c5912e4920bb4fa1979d63d47e7f430e87e3820fMakoto Onuki 173a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blankpackage com.android.emailcommon.utility; 18c5912e4920bb4fa1979d63d47e7f430e87e3820fMakoto Onuki 1978959916e771114ff8c48fc181e34a7dff0aa672Ben Komaloimport android.content.Context; 20c5912e4920bb4fa1979d63d47e7f430e87e3820fMakoto Onukiimport android.net.SSLCertificateSocketFactory; 2178959916e771114ff8c48fc181e34a7dff0aa672Ben Komaloimport android.security.KeyChain; 2278959916e771114ff8c48fc181e34a7dff0aa672Ben Komaloimport android.security.KeyChainException; 2378959916e771114ff8c48fc181e34a7dff0aa672Ben Komaloimport android.util.Log; 24c5912e4920bb4fa1979d63d47e7f430e87e3820fMakoto Onuki 25f4f10a3fdf3fdf94db4780017c4392823942b1d7Ben Komaloimport com.google.common.annotations.VisibleForTesting; 26f4f10a3fdf3fdf94db4780017c4392823942b1d7Ben Komalo 27f4f10a3fdf3fdf94db4780017c4392823942b1d7Ben Komaloimport java.net.InetAddress; 2878959916e771114ff8c48fc181e34a7dff0aa672Ben Komaloimport java.net.Socket; 2978959916e771114ff8c48fc181e34a7dff0aa672Ben Komaloimport java.security.Principal; 3078959916e771114ff8c48fc181e34a7dff0aa672Ben Komaloimport java.security.PrivateKey; 31cb24e515b7983133133ca38bd3e3e6354daaab76Ben Komaloimport java.security.cert.CertificateException; 3278959916e771114ff8c48fc181e34a7dff0aa672Ben Komaloimport java.security.cert.X509Certificate; 3378959916e771114ff8c48fc181e34a7dff0aa672Ben Komaloimport java.util.Arrays; 3478959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo 3578959916e771114ff8c48fc181e34a7dff0aa672Ben Komaloimport javax.net.ssl.KeyManager; 3678959916e771114ff8c48fc181e34a7dff0aa672Ben Komaloimport javax.net.ssl.X509ExtendedKeyManager; 37c5912e4920bb4fa1979d63d47e7f430e87e3820fMakoto Onuki 38c5912e4920bb4fa1979d63d47e7f430e87e3820fMakoto Onukipublic class SSLUtils { 3978959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo private static SSLCertificateSocketFactory sInsecureFactory; 4078959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo private static SSLCertificateSocketFactory sSecureFactory; 4178959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo 4278959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo private static final boolean LOG_ENABLED = false; 4378959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo private static final String TAG = "Email.Ssl"; 44c5912e4920bb4fa1979d63d47e7f430e87e3820fMakoto Onuki 45c5912e4920bb4fa1979d63d47e7f430e87e3820fMakoto Onuki /** 4678959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo * Returns a {@link javax.net.ssl.SSLSocketFactory}. 4778959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo * Optionally bypass all SSL certificate checks. 48c5912e4920bb4fa1979d63d47e7f430e87e3820fMakoto Onuki * 49c5912e4920bb4fa1979d63d47e7f430e87e3820fMakoto Onuki * @param insecure if true, bypass all SSL certificate checks 50c5912e4920bb4fa1979d63d47e7f430e87e3820fMakoto Onuki */ 51877b9070fa4d7a6b51ae1f75640a6c23cc86c963Ben Komalo public synchronized static SSLCertificateSocketFactory getSSLSocketFactory( 5278959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo boolean insecure) { 53c5912e4920bb4fa1979d63d47e7f430e87e3820fMakoto Onuki if (insecure) { 54c5912e4920bb4fa1979d63d47e7f430e87e3820fMakoto Onuki if (sInsecureFactory == null) { 5578959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo sInsecureFactory = (SSLCertificateSocketFactory) 5678959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo SSLCertificateSocketFactory.getInsecure(0, null); 57c5912e4920bb4fa1979d63d47e7f430e87e3820fMakoto Onuki } 58c5912e4920bb4fa1979d63d47e7f430e87e3820fMakoto Onuki return sInsecureFactory; 59c5912e4920bb4fa1979d63d47e7f430e87e3820fMakoto Onuki } else { 60c5912e4920bb4fa1979d63d47e7f430e87e3820fMakoto Onuki if (sSecureFactory == null) { 6178959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo sSecureFactory = (SSLCertificateSocketFactory) 6278959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo SSLCertificateSocketFactory.getDefault(0, null); 63c5912e4920bb4fa1979d63d47e7f430e87e3820fMakoto Onuki } 64c5912e4920bb4fa1979d63d47e7f430e87e3820fMakoto Onuki return sSecureFactory; 65c5912e4920bb4fa1979d63d47e7f430e87e3820fMakoto Onuki } 66c5912e4920bb4fa1979d63d47e7f430e87e3820fMakoto Onuki } 67724c3a81cd3649b48ab47c6e49cb42f73f20c815Ben Komalo 68724c3a81cd3649b48ab47c6e49cb42f73f20c815Ben Komalo /** 6978959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo * Returns a {@link org.apache.http.conn.ssl.SSLSocketFactory SSLSocketFactory} for use with the 7078959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo * Apache HTTP stack. 7178959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo */ 72f4dbbf10996e6bca926a5825bbc69e1e172c20c0Ben Komalo public static SSLSocketFactory getHttpSocketFactory(boolean insecure, KeyManager keyManager) { 7378959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo SSLCertificateSocketFactory underlying = getSSLSocketFactory(insecure); 74f4dbbf10996e6bca926a5825bbc69e1e172c20c0Ben Komalo if (keyManager != null) { 75f4dbbf10996e6bca926a5825bbc69e1e172c20c0Ben Komalo underlying.setKeyManagers(new KeyManager[] { keyManager }); 76f4dbbf10996e6bca926a5825bbc69e1e172c20c0Ben Komalo } 774d3f3f3ab95c03d4c1ab308801b92ba1d9df2276Ben Komalo SSLSocketFactory wrapped = new SSLSocketFactory(underlying); 784d3f3f3ab95c03d4c1ab308801b92ba1d9df2276Ben Komalo if (insecure) { 794d3f3f3ab95c03d4c1ab308801b92ba1d9df2276Ben Komalo wrapped.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); 804d3f3f3ab95c03d4c1ab308801b92ba1d9df2276Ben Komalo } 814d3f3f3ab95c03d4c1ab308801b92ba1d9df2276Ben Komalo return wrapped; 8278959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo } 8378959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo 8478959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo /** 85724c3a81cd3649b48ab47c6e49cb42f73f20c815Ben Komalo * Escapes the contents a string to be used as a safe scheme name in the URI according to 86724c3a81cd3649b48ab47c6e49cb42f73f20c815Ben Komalo * http://tools.ietf.org/html/rfc3986#section-3.1 87724c3a81cd3649b48ab47c6e49cb42f73f20c815Ben Komalo * 88724c3a81cd3649b48ab47c6e49cb42f73f20c815Ben Komalo * This does not ensure that the first character is a letter (which is required by the RFC). 89724c3a81cd3649b48ab47c6e49cb42f73f20c815Ben Komalo */ 90745b33b8ff55e9a9c4871f07f9d97db893f784b2Makoto Onuki @VisibleForTesting 91724c3a81cd3649b48ab47c6e49cb42f73f20c815Ben Komalo public static String escapeForSchemeName(String s) { 92724c3a81cd3649b48ab47c6e49cb42f73f20c815Ben Komalo // According to the RFC, scheme names are case-insensitive. 93724c3a81cd3649b48ab47c6e49cb42f73f20c815Ben Komalo s = s.toLowerCase(); 94724c3a81cd3649b48ab47c6e49cb42f73f20c815Ben Komalo 95724c3a81cd3649b48ab47c6e49cb42f73f20c815Ben Komalo StringBuilder sb = new StringBuilder(); 96724c3a81cd3649b48ab47c6e49cb42f73f20c815Ben Komalo for (int i = 0; i < s.length(); i++) { 97724c3a81cd3649b48ab47c6e49cb42f73f20c815Ben Komalo char c = s.charAt(i); 98724c3a81cd3649b48ab47c6e49cb42f73f20c815Ben Komalo if (Character.isLetter(c) || Character.isDigit(c) 99724c3a81cd3649b48ab47c6e49cb42f73f20c815Ben Komalo || ('-' == c) || ('.' == c)) { 100724c3a81cd3649b48ab47c6e49cb42f73f20c815Ben Komalo // Safe - use as is. 101724c3a81cd3649b48ab47c6e49cb42f73f20c815Ben Komalo sb.append(c); 102724c3a81cd3649b48ab47c6e49cb42f73f20c815Ben Komalo } else if ('+' == c) { 103724c3a81cd3649b48ab47c6e49cb42f73f20c815Ben Komalo // + is used as our escape character, so double it up. 104724c3a81cd3649b48ab47c6e49cb42f73f20c815Ben Komalo sb.append("++"); 105724c3a81cd3649b48ab47c6e49cb42f73f20c815Ben Komalo } else { 106724c3a81cd3649b48ab47c6e49cb42f73f20c815Ben Komalo // Unsafe - escape. 107724c3a81cd3649b48ab47c6e49cb42f73f20c815Ben Komalo sb.append('+').append((int) c); 108724c3a81cd3649b48ab47c6e49cb42f73f20c815Ben Komalo } 109724c3a81cd3649b48ab47c6e49cb42f73f20c815Ben Komalo } 110724c3a81cd3649b48ab47c6e49cb42f73f20c815Ben Komalo return sb.toString(); 111724c3a81cd3649b48ab47c6e49cb42f73f20c815Ben Komalo } 11278959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo 11378959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo private static abstract class StubKeyManager extends X509ExtendedKeyManager { 11478959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo @Override public abstract String chooseClientAlias( 11578959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo String[] keyTypes, Principal[] issuers, Socket socket); 11678959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo 11778959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo @Override public abstract X509Certificate[] getCertificateChain(String alias); 11878959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo 11978959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo @Override public abstract PrivateKey getPrivateKey(String alias); 12078959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo 12178959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo 12278959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo // The following methods are unused. 12378959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo 12478959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo @Override 12578959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo public final String chooseServerAlias( 12678959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo String keyType, Principal[] issuers, Socket socket) { 12778959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo // not a client SSLSocket callback 12878959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo throw new UnsupportedOperationException(); 12978959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo } 13078959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo 13178959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo @Override 13278959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo public final String[] getClientAliases(String keyType, Principal[] issuers) { 13378959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo // not a client SSLSocket callback 13478959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo throw new UnsupportedOperationException(); 13578959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo } 13678959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo 13778959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo @Override 13878959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo public final String[] getServerAliases(String keyType, Principal[] issuers) { 13978959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo // not a client SSLSocket callback 14078959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo throw new UnsupportedOperationException(); 14178959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo } 14278959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo } 14378959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo 14478959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo /** 145f4f10a3fdf3fdf94db4780017c4392823942b1d7Ben Komalo * A dummy {@link KeyManager} which keeps track of the last time a server has requested 146f4f10a3fdf3fdf94db4780017c4392823942b1d7Ben Komalo * a client certificate. 147f4dbbf10996e6bca926a5825bbc69e1e172c20c0Ben Komalo */ 148f4dbbf10996e6bca926a5825bbc69e1e172c20c0Ben Komalo public static class TrackingKeyManager extends StubKeyManager { 149f4f10a3fdf3fdf94db4780017c4392823942b1d7Ben Komalo private volatile long mLastTimeCertRequested = 0L; 150f4f10a3fdf3fdf94db4780017c4392823942b1d7Ben Komalo 151f4dbbf10996e6bca926a5825bbc69e1e172c20c0Ben Komalo @Override 152f4dbbf10996e6bca926a5825bbc69e1e172c20c0Ben Komalo public String chooseClientAlias(String[] keyTypes, Principal[] issuers, Socket socket) { 153f4dbbf10996e6bca926a5825bbc69e1e172c20c0Ben Komalo if (LOG_ENABLED) { 154f4f10a3fdf3fdf94db4780017c4392823942b1d7Ben Komalo InetAddress address = socket.getInetAddress(); 155f4dbbf10996e6bca926a5825bbc69e1e172c20c0Ben Komalo Log.i(TAG, "TrackingKeyManager: requesting a client cert alias for " 156f4f10a3fdf3fdf94db4780017c4392823942b1d7Ben Komalo + address.getCanonicalHostName()); 157f4dbbf10996e6bca926a5825bbc69e1e172c20c0Ben Komalo } 158f4f10a3fdf3fdf94db4780017c4392823942b1d7Ben Komalo mLastTimeCertRequested = System.currentTimeMillis(); 159f4f10a3fdf3fdf94db4780017c4392823942b1d7Ben Komalo return null; 160f4dbbf10996e6bca926a5825bbc69e1e172c20c0Ben Komalo } 161f4dbbf10996e6bca926a5825bbc69e1e172c20c0Ben Komalo 162f4dbbf10996e6bca926a5825bbc69e1e172c20c0Ben Komalo @Override 163f4dbbf10996e6bca926a5825bbc69e1e172c20c0Ben Komalo public X509Certificate[] getCertificateChain(String alias) { 164f4f10a3fdf3fdf94db4780017c4392823942b1d7Ben Komalo if (LOG_ENABLED) { 165f4f10a3fdf3fdf94db4780017c4392823942b1d7Ben Komalo Log.i(TAG, "TrackingKeyManager: returning a null cert chain"); 166f4f10a3fdf3fdf94db4780017c4392823942b1d7Ben Komalo } 167f4dbbf10996e6bca926a5825bbc69e1e172c20c0Ben Komalo return null; 168f4dbbf10996e6bca926a5825bbc69e1e172c20c0Ben Komalo } 169f4dbbf10996e6bca926a5825bbc69e1e172c20c0Ben Komalo 170f4dbbf10996e6bca926a5825bbc69e1e172c20c0Ben Komalo @Override 171f4dbbf10996e6bca926a5825bbc69e1e172c20c0Ben Komalo public PrivateKey getPrivateKey(String alias) { 172f4f10a3fdf3fdf94db4780017c4392823942b1d7Ben Komalo if (LOG_ENABLED) { 173f4f10a3fdf3fdf94db4780017c4392823942b1d7Ben Komalo Log.i(TAG, "TrackingKeyManager: returning a null private key"); 174f4f10a3fdf3fdf94db4780017c4392823942b1d7Ben Komalo } 175f4dbbf10996e6bca926a5825bbc69e1e172c20c0Ben Komalo return null; 176f4dbbf10996e6bca926a5825bbc69e1e172c20c0Ben Komalo } 177f4dbbf10996e6bca926a5825bbc69e1e172c20c0Ben Komalo 178f4f10a3fdf3fdf94db4780017c4392823942b1d7Ben Komalo /** 179f4f10a3fdf3fdf94db4780017c4392823942b1d7Ben Komalo * @return the last time that this {@link KeyManager} detected a request by a server 180f4f10a3fdf3fdf94db4780017c4392823942b1d7Ben Komalo * for a client certificate (in millis since epoch). 181f4f10a3fdf3fdf94db4780017c4392823942b1d7Ben Komalo */ 182f4f10a3fdf3fdf94db4780017c4392823942b1d7Ben Komalo public long getLastCertReqTime() { 183f4f10a3fdf3fdf94db4780017c4392823942b1d7Ben Komalo return mLastTimeCertRequested; 184f4f10a3fdf3fdf94db4780017c4392823942b1d7Ben Komalo } 185f4dbbf10996e6bca926a5825bbc69e1e172c20c0Ben Komalo } 186f4dbbf10996e6bca926a5825bbc69e1e172c20c0Ben Komalo 187f4dbbf10996e6bca926a5825bbc69e1e172c20c0Ben Komalo /** 18878959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo * A {@link KeyManager} that reads uses credentials stored in the system {@link KeyChain}. 18978959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo */ 19078959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo public static class KeyChainKeyManager extends StubKeyManager { 19178959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo private final String mClientAlias; 19278959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo private final X509Certificate[] mCertificateChain; 19378959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo private final PrivateKey mPrivateKey; 19478959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo 19578959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo /** 19678959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo * Builds an instance of a KeyChainKeyManager using the given certificate alias. 19778959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo * If for any reason retrieval of the credentials from the system {@link KeyChain} fails, 19878959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo * a {@code null} value will be returned. 19978959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo */ 200cb24e515b7983133133ca38bd3e3e6354daaab76Ben Komalo public static KeyChainKeyManager fromAlias(Context context, String alias) 201cb24e515b7983133133ca38bd3e3e6354daaab76Ben Komalo throws CertificateException { 20278959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo X509Certificate[] certificateChain; 20378959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo try { 20478959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo certificateChain = KeyChain.getCertificateChain(context, alias); 20578959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo } catch (KeyChainException e) { 206f4dbbf10996e6bca926a5825bbc69e1e172c20c0Ben Komalo logError(alias, "certificate chain", e); 207cb24e515b7983133133ca38bd3e3e6354daaab76Ben Komalo throw new CertificateException(e); 20878959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo } catch (InterruptedException e) { 209f4dbbf10996e6bca926a5825bbc69e1e172c20c0Ben Komalo logError(alias, "certificate chain", e); 210cb24e515b7983133133ca38bd3e3e6354daaab76Ben Komalo throw new CertificateException(e); 21178959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo } 21278959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo 21378959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo PrivateKey privateKey; 21478959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo try { 21578959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo privateKey = KeyChain.getPrivateKey(context, alias); 21678959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo } catch (KeyChainException e) { 217f4dbbf10996e6bca926a5825bbc69e1e172c20c0Ben Komalo logError(alias, "private key", e); 218cb24e515b7983133133ca38bd3e3e6354daaab76Ben Komalo throw new CertificateException(e); 21978959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo } catch (InterruptedException e) { 220f4dbbf10996e6bca926a5825bbc69e1e172c20c0Ben Komalo logError(alias, "private key", e); 221cb24e515b7983133133ca38bd3e3e6354daaab76Ben Komalo throw new CertificateException(e); 222cb24e515b7983133133ca38bd3e3e6354daaab76Ben Komalo } 223cb24e515b7983133133ca38bd3e3e6354daaab76Ben Komalo 224cb24e515b7983133133ca38bd3e3e6354daaab76Ben Komalo if (certificateChain == null || privateKey == null) { 225877b9070fa4d7a6b51ae1f75640a6c23cc86c963Ben Komalo throw new CertificateException("Can't access certificate from keystore"); 22678959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo } 22778959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo 22878959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo return new KeyChainKeyManager(alias, certificateChain, privateKey); 22978959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo } 23078959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo 231f4dbbf10996e6bca926a5825bbc69e1e172c20c0Ben Komalo private static void logError(String alias, String type, Exception ex) { 232877b9070fa4d7a6b51ae1f75640a6c23cc86c963Ben Komalo // Avoid logging PII when explicit logging is not on. 233877b9070fa4d7a6b51ae1f75640a6c23cc86c963Ben Komalo if (LOG_ENABLED) { 234877b9070fa4d7a6b51ae1f75640a6c23cc86c963Ben Komalo Log.e(TAG, "Unable to retrieve " + type + " for [" + alias + "] due to " + ex); 235877b9070fa4d7a6b51ae1f75640a6c23cc86c963Ben Komalo } else { 236877b9070fa4d7a6b51ae1f75640a6c23cc86c963Ben Komalo Log.e(TAG, "Unable to retrieve " + type + " due to " + ex); 237877b9070fa4d7a6b51ae1f75640a6c23cc86c963Ben Komalo } 238f4dbbf10996e6bca926a5825bbc69e1e172c20c0Ben Komalo } 239f4dbbf10996e6bca926a5825bbc69e1e172c20c0Ben Komalo 24078959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo private KeyChainKeyManager( 24178959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo String clientAlias, X509Certificate[] certificateChain, PrivateKey privateKey) { 24278959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo mClientAlias = clientAlias; 24378959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo mCertificateChain = certificateChain; 24478959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo mPrivateKey = privateKey; 24578959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo } 24678959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo 24778959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo 24878959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo @Override 24978959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo public String chooseClientAlias(String[] keyTypes, Principal[] issuers, Socket socket) { 25078959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo if (LOG_ENABLED) { 25178959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo Log.i(TAG, "Requesting a client cert alias for " + Arrays.toString(keyTypes)); 25278959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo } 25378959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo return mClientAlias; 25478959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo } 25578959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo 25678959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo @Override 25778959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo public X509Certificate[] getCertificateChain(String alias) { 25878959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo if (LOG_ENABLED) { 25978959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo Log.i(TAG, "Requesting a client certificate chain for alias [" + alias + "]"); 26078959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo } 26178959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo return mCertificateChain; 26278959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo } 26378959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo 26478959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo @Override 26578959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo public PrivateKey getPrivateKey(String alias) { 26678959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo if (LOG_ENABLED) { 26778959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo Log.i(TAG, "Requesting a client private key for alias [" + alias + "]"); 26878959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo } 26978959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo return mPrivateKey; 27078959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo } 27178959916e771114ff8c48fc181e34a7dff0aa672Ben Komalo } 272c5912e4920bb4fa1979d63d47e7f430e87e3820fMakoto Onuki} 273