package com.android.hotspot2.osu; import android.util.Log; 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.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.net.ssl.X509KeyManager; import javax.security.auth.x500.X500Principal; public class WiFiKeyManager implements X509KeyManager { private final KeyStore mKeyStore; private final Map<X500Principal, String[]> mAliases = new HashMap<>(); public WiFiKeyManager(KeyStore keyStore) throws IOException { mKeyStore = keyStore; } public void enableClientAuth(List<String> issuerNames) throws GeneralSecurityException, IOException { Set<X500Principal> acceptedIssuers = new HashSet<>(); for (String issuerName : issuerNames) { acceptedIssuers.add(new X500Principal(issuerName)); } Enumeration<String> aliases = mKeyStore.aliases(); while (aliases.hasMoreElements()) { String alias = aliases.nextElement(); Certificate cert = mKeyStore.getCertificate(alias); if ((cert instanceof X509Certificate) && mKeyStore.getKey(alias, null) != null) { X509Certificate x509Certificate = (X509Certificate) cert; X500Principal issuer = x509Certificate.getIssuerX500Principal(); if (acceptedIssuers.contains(issuer)) { mAliases.put(issuer, new String[]{alias, cert.getPublicKey().getAlgorithm()}); } } } if (mAliases.isEmpty()) { throw new IOException("No aliases match requested issuers: " + issuerNames); } } private static class AliasEntry implements Comparable<AliasEntry> { private final int mPreference; private final String mAlias; private AliasEntry(int preference, String alias) { mPreference = preference; mAlias = alias; } public int getPreference() { return mPreference; } public String getAlias() { return mAlias; } @Override public int compareTo(AliasEntry other) { return Integer.compare(getPreference(), other.getPreference()); } } @Override public String chooseClientAlias(String[] keyTypes, Principal[] issuers, Socket socket) { Map<String, Integer> keyPrefs = new HashMap<>(keyTypes.length); int pref = 0; for (String keyType : keyTypes) { keyPrefs.put(keyType, pref++); } List<AliasEntry> aliases = new ArrayList<>(); if (issuers != null) { for (Principal issuer : issuers) { if (issuer instanceof X500Principal) { String[] aliasAndKey = mAliases.get((X500Principal) issuer); if (aliasAndKey != null) { Integer preference = keyPrefs.get(aliasAndKey[1]); if (preference != null) { aliases.add(new AliasEntry(preference, aliasAndKey[0])); } } } } } else { for (String[] aliasAndKey : mAliases.values()) { Integer preference = keyPrefs.get(aliasAndKey[1]); if (preference != null) { aliases.add(new AliasEntry(preference, aliasAndKey[0])); } } } Collections.sort(aliases); return aliases.isEmpty() ? null : aliases.get(0).getAlias(); } @Override public String[] getClientAliases(String keyType, Principal[] issuers) { List<String> aliases = new ArrayList<>(); if (issuers != null) { for (Principal issuer : issuers) { if (issuer instanceof X500Principal) { String[] aliasAndKey = mAliases.get((X500Principal) issuer); if (aliasAndKey != null) { aliases.add(aliasAndKey[0]); } } } } else { for (String[] aliasAndKey : mAliases.values()) { aliases.add(aliasAndKey[0]); } } return aliases.isEmpty() ? null : aliases.toArray(new String[aliases.size()]); } @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) { try { List<X509Certificate> certs = new ArrayList<>(); for (Certificate certificate : mKeyStore.getCertificateChain(alias)) { 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; } } @Override public PrivateKey getPrivateKey(String alias) { try { return (PrivateKey) mKeyStore.getKey(alias, null); } catch (GeneralSecurityException gse) { Log.w(OSUManager.TAG, "Failed to retrieve private key: " + gse); return null; } } }