package com.android.hotspot2.osu; import android.util.Log; import com.android.hotspot2.pps.HomeSP; import java.io.IOException; import java.net.Socket; import java.security.GeneralSecurityException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.Principal; import java.security.PrivateKey; import java.security.cert.Certificate; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.net.ssl.X509KeyManager; public class ClientKeyManager implements X509KeyManager { private final KeyStore mKeyStore; private final Map<OSUCertType, String> mAliasMap; private final Map<OSUCertType, Object> mTempKeys; private static final String sTempAlias = "client-alias"; public ClientKeyManager(HomeSP homeSP, KeyStore keyStore) throws IOException { mKeyStore = keyStore; mAliasMap = new HashMap<>(); mAliasMap.put(OSUCertType.AAA, OSUManager.CERT_CLT_CA_ALIAS + homeSP.getFQDN()); mAliasMap.put(OSUCertType.Client, OSUManager.CERT_CLT_CERT_ALIAS + homeSP.getFQDN()); mAliasMap.put(OSUCertType.PrivateKey, OSUManager.CERT_CLT_KEY_ALIAS + homeSP.getFQDN()); mTempKeys = new HashMap<>(); } public void reloadKeys(Map<OSUCertType, List<X509Certificate>> certs, PrivateKey key) throws IOException { List<X509Certificate> clientCerts = certs.get(OSUCertType.Client); X509Certificate[] certArray = new X509Certificate[clientCerts.size()]; int n = 0; for (X509Certificate cert : clientCerts) { certArray[n++] = cert; } mTempKeys.put(OSUCertType.Client, certArray); mTempKeys.put(OSUCertType.PrivateKey, key); } @Override public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) { if (mTempKeys.isEmpty()) { return mAliasMap.get(OSUCertType.Client); } else { return sTempAlias; } } @Override public String[] getClientAliases(String keyType, Principal[] issuers) { if (mTempKeys.isEmpty()) { String alias = mAliasMap.get(OSUCertType.Client); return alias != null ? new String[]{alias} : null; } else { return new String[]{sTempAlias}; } } @Override public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) { throw new UnsupportedOperationException(); } @Override public String[] getServerAliases(String keyType, Principal[] issuers) { throw new UnsupportedOperationException(); } @Override public X509Certificate[] getCertificateChain(String alias) { if (mTempKeys.isEmpty()) { if (!mAliasMap.get(OSUCertType.Client).equals(alias)) { Log.w(OSUManager.TAG, "Bad cert alias requested: '" + alias + "'"); return null; } try { List<X509Certificate> certs = new ArrayList<>(); for (Certificate certificate : mKeyStore.getCertificateChain(mAliasMap.get(OSUCertType.Client))) { if (certificate instanceof X509Certificate) { certs.add((X509Certificate) certificate); } } return certs.toArray(new X509Certificate[certs.size()]); } catch (KeyStoreException kse) { Log.w(OSUManager.TAG, "Failed to retrieve certificates: " + kse); return null; } } else if (sTempAlias.equals(alias)) { return (X509Certificate[]) mTempKeys.get(OSUCertType.Client); } else { Log.w(OSUManager.TAG, "Bad cert alias requested: '" + alias + "'"); return null; } } @Override public PrivateKey getPrivateKey(String alias) { if (mTempKeys.isEmpty()) { if (!mAliasMap.get(OSUCertType.Client).equals(alias)) { Log.w(OSUManager.TAG, "Bad key alias requested: '" + alias + "'"); } try { return (PrivateKey) mKeyStore.getKey(mAliasMap.get(OSUCertType.PrivateKey), null); } catch (GeneralSecurityException gse) { Log.w(OSUManager.TAG, "Failed to retrieve private key: " + gse); return null; } } else if (sTempAlias.equals(alias)) { return (PrivateKey) mTempKeys.get(OSUCertType.PrivateKey); } else { Log.w(OSUManager.TAG, "Bad cert alias requested: '" + alias + "'"); return null; } } }