1ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistpackage com.android.hotspot2.osu;
2ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
3ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport android.util.Log;
4ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
5ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport com.android.hotspot2.pps.HomeSP;
6ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
7ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.io.IOException;
8ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.net.Socket;
9ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.security.GeneralSecurityException;
10ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.security.KeyStore;
11ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.security.KeyStoreException;
12ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.security.Principal;
13ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.security.PrivateKey;
14ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.security.cert.Certificate;
15ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.security.cert.X509Certificate;
16ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.ArrayList;
17ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.HashMap;
18ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.List;
19ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.Map;
20ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
21ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport javax.net.ssl.X509KeyManager;
22ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
23ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistpublic class ClientKeyManager implements X509KeyManager {
24ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    private final KeyStore mKeyStore;
25ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    private final Map<OSUCertType, String> mAliasMap;
26ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    private final Map<OSUCertType, Object> mTempKeys;
27ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
28ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    private static final String sTempAlias = "client-alias";
29ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
30ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public ClientKeyManager(HomeSP homeSP, KeyStore keyStore) throws IOException {
31ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        mKeyStore = keyStore;
32ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        mAliasMap = new HashMap<>();
33ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        mAliasMap.put(OSUCertType.AAA, OSUManager.CERT_CLT_CA_ALIAS + homeSP.getFQDN());
34ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        mAliasMap.put(OSUCertType.Client, OSUManager.CERT_CLT_CERT_ALIAS + homeSP.getFQDN());
35ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        mAliasMap.put(OSUCertType.PrivateKey, OSUManager.CERT_CLT_KEY_ALIAS + homeSP.getFQDN());
36ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        mTempKeys = new HashMap<>();
37ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
38ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
39ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public void reloadKeys(Map<OSUCertType, List<X509Certificate>> certs, PrivateKey key)
40ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            throws IOException {
41ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        List<X509Certificate> clientCerts = certs.get(OSUCertType.Client);
42ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        X509Certificate[] certArray = new X509Certificate[clientCerts.size()];
43ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        int n = 0;
44ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        for (X509Certificate cert : clientCerts) {
45ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            certArray[n++] = cert;
46ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
47ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        mTempKeys.put(OSUCertType.Client, certArray);
48ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        mTempKeys.put(OSUCertType.PrivateKey, key);
49ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
50ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
51ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    @Override
52ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
53ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (mTempKeys.isEmpty()) {
54ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            return mAliasMap.get(OSUCertType.Client);
55ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        } else {
56ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            return sTempAlias;
57ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
58ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
59ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
60ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    @Override
61ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public String[] getClientAliases(String keyType, Principal[] issuers) {
62ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (mTempKeys.isEmpty()) {
63ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            String alias = mAliasMap.get(OSUCertType.Client);
64ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            return alias != null ? new String[]{alias} : null;
65ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        } else {
66ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            return new String[]{sTempAlias};
67ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
68ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
69ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
70ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    @Override
71ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
72ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        throw new UnsupportedOperationException();
73ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
74ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
75ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    @Override
76ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public String[] getServerAliases(String keyType, Principal[] issuers) {
77ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        throw new UnsupportedOperationException();
78ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
79ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
80ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    @Override
81ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public X509Certificate[] getCertificateChain(String alias) {
82ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (mTempKeys.isEmpty()) {
83ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            if (!mAliasMap.get(OSUCertType.Client).equals(alias)) {
84ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                Log.w(OSUManager.TAG, "Bad cert alias requested: '" + alias + "'");
85ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                return null;
86ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
87ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            try {
88ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                List<X509Certificate> certs = new ArrayList<>();
89ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                for (Certificate certificate :
90ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                        mKeyStore.getCertificateChain(mAliasMap.get(OSUCertType.Client))) {
91ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    if (certificate instanceof X509Certificate) {
92ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                        certs.add((X509Certificate) certificate);
93ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                    }
94ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                }
95ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                return certs.toArray(new X509Certificate[certs.size()]);
96ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            } catch (KeyStoreException kse) {
97ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                Log.w(OSUManager.TAG, "Failed to retrieve certificates: " + kse);
98ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                return null;
99ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
100ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        } else if (sTempAlias.equals(alias)) {
101ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            return (X509Certificate[]) mTempKeys.get(OSUCertType.Client);
102ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        } else {
103ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            Log.w(OSUManager.TAG, "Bad cert alias requested: '" + alias + "'");
104ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            return null;
105ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
106ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
107ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist
108ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    @Override
109ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    public PrivateKey getPrivateKey(String alias) {
110ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        if (mTempKeys.isEmpty()) {
111ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            if (!mAliasMap.get(OSUCertType.Client).equals(alias)) {
112ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                Log.w(OSUManager.TAG, "Bad key alias requested: '" + alias + "'");
113ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
114ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            try {
115ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                return (PrivateKey) mKeyStore.getKey(mAliasMap.get(OSUCertType.PrivateKey), null);
116ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            } catch (GeneralSecurityException gse) {
117ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                Log.w(OSUManager.TAG, "Failed to retrieve private key: " + gse);
118ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist                return null;
119ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            }
120ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        } else if (sTempAlias.equals(alias)) {
121ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            return (PrivateKey) mTempKeys.get(OSUCertType.PrivateKey);
122ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        } else {
123ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            Log.w(OSUManager.TAG, "Bad cert alias requested: '" + alias + "'");
124ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist            return null;
125ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist        }
126ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist    }
127ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist}
128