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