1package org.apache.harmony.security.tests.support;
2
3import org.apache.harmony.security.tests.support.cert.MyCertificate;
4
5import java.io.IOException;
6import java.io.InputStream;
7import java.io.OutputStream;
8import java.security.Key;
9import java.security.KeyStoreException;
10import java.security.KeyStoreSpi;
11import java.security.NoSuchAlgorithmException;
12import java.security.PrivateKey;
13import java.security.UnrecoverableKeyException;
14import java.security.KeyStore.LoadStoreParameter;
15import java.security.KeyStore.PasswordProtection;
16import java.security.KeyStore.ProtectionParameter;
17import java.security.cert.Certificate;
18import java.security.cert.CertificateException;
19import java.util.Collections;
20import java.util.Date;
21import java.util.Enumeration;
22import java.util.HashMap;
23import java.util.Map;
24
25import javax.crypto.SecretKey;
26
27public class TestKeyStoreSpi extends KeyStoreSpi {
28
29    Map<String, Object> aliases = new HashMap<String, Object>();
30
31    public static final Certificate CERT = new MyCertificate("certtype",
32            new byte[] {});
33    public static final Certificate[] CERTCHAIN = new Certificate[] {
34            new MyCertificate("cert1", new byte[] {}),
35            new MyCertificate("cert2", new byte[] {})};
36
37    public static final Key KEY = new SecretKey() {
38
39        public String getAlgorithm() {
40            return "secret";
41        }
42
43        public byte[] getEncoded() {
44            return new byte[] {42};
45        }
46
47        public String getFormat() {
48            return "format";
49        }
50
51    };
52
53    public static final Object DUMMY = new Object();
54
55    public TestKeyStoreSpi() {
56        aliases.put("certalias", CERT);
57        aliases.put("chainalias", CERTCHAIN);
58        aliases.put("keyalias", KEY);
59        aliases.put("unknownalias", DUMMY);
60    }
61
62    @Override
63    public Enumeration<String> engineAliases() {
64        return Collections.enumeration(aliases.keySet());
65    }
66
67    @Override
68    public boolean engineContainsAlias(String alias) {
69        return aliases.containsKey(alias);
70    }
71
72    @Override
73    public void engineDeleteEntry(String alias) throws KeyStoreException {
74        throw new KeyStoreException("entry " + alias + " cannot be deleted");
75    }
76
77    @Override
78    public Certificate engineGetCertificate(String alias) {
79        return (Certificate) aliases.get(alias);
80    }
81
82    @Override
83    public String engineGetCertificateAlias(Certificate cert) {
84        if (cert == null) {
85            throw new NullPointerException();
86        }
87
88        for (Map.Entry<String, Object> alias : aliases.entrySet()) {
89            if (alias.getValue() == cert) {
90                return alias.getKey();
91            }
92        }
93
94        return null;
95    }
96
97    @Override
98    public Certificate[] engineGetCertificateChain(String alias) {
99        return (Certificate[]) aliases.get(alias);
100    }
101
102    @Override
103    public Date engineGetCreationDate(String alias) {
104        return new Date(42 * 1024 * 1024);
105    }
106
107    @Override
108    public Key engineGetKey(String alias, char[] password)
109            throws NoSuchAlgorithmException, UnrecoverableKeyException {
110        if (engineContainsAlias(alias)) {
111            if (!engineIsKeyEntry(alias)) {
112                if (password == null) {
113                    throw new NoSuchAlgorithmException("no such alg");
114                } else {
115                    throw new UnrecoverableKeyException();
116                }
117
118            }
119            return (Key) aliases.get(alias);
120        }
121
122        throw new UnrecoverableKeyException();
123    }
124
125    @Override
126    public boolean engineIsCertificateEntry(String alias) {
127        try {
128            Certificate c = (Certificate) aliases.get(alias);
129            return true;
130        } catch (ClassCastException e) {
131            return false;
132        }
133    }
134
135    @Override
136    public boolean engineIsKeyEntry(String alias) {
137        try {
138            Key k = (Key) aliases.get(alias);
139            return true;
140        } catch (ClassCastException e) {
141            return false;
142        }
143    }
144
145    @Override
146    public void engineLoad(InputStream stream, char[] password)
147            throws IOException, NoSuchAlgorithmException, CertificateException {
148        if (stream != null) {
149            if (stream.available() == 0)
150            {
151                throw new IOException();
152            }
153        }
154        if (password == null) {
155            throw new NoSuchAlgorithmException();
156        } else if (password.length == 0) {
157            throw new CertificateException();
158        }
159    }
160
161    @Override
162    public void engineLoad(LoadStoreParameter param) throws IOException,
163            NoSuchAlgorithmException, CertificateException {
164        if (param == null) {
165            engineLoad(null, null);
166            return;
167        }
168
169        ProtectionParameter pParam = param.getProtectionParameter();
170        if (pParam == null) {
171            throw new NoSuchAlgorithmException();
172        }
173
174        if (pParam instanceof PasswordProtection) {
175            char[] password = ((PasswordProtection) pParam).getPassword();
176            if (password == null) {
177                throw new NoSuchAlgorithmException();
178            } else {
179                return;
180            }
181        }
182        throw new CertificateException();
183    }
184
185    @Override
186    public void engineSetCertificateEntry(String alias, Certificate cert)
187            throws KeyStoreException {
188        if (engineContainsAlias(alias)) {
189            if (!engineIsCertificateEntry(alias)) {
190                throw new KeyStoreException("alias is not a cert entry");
191            }
192        }
193        aliases.put(alias, cert);
194    }
195
196    @Override
197    public void engineSetKeyEntry(String alias, Key key, char[] password,
198            Certificate[] chain) throws KeyStoreException {
199        if (engineContainsAlias(alias)) {
200            if (!engineIsKeyEntry(alias)) {
201                throw new KeyStoreException("alias is not a key enrty");
202            }
203        }
204
205        if (key instanceof PrivateKey)
206        {
207            if (chain == null || chain.length == 0) {
208                throw new IllegalArgumentException();
209            }
210        }
211
212        aliases.put(alias, key);
213    }
214
215    @Override
216    public void engineSetKeyEntry(String alias, byte[] key, Certificate[] chain)
217            throws KeyStoreException {
218        throw new KeyStoreException("set entry failed");
219    }
220
221    @Override
222    public int engineSize() {
223        return aliases.size();
224    }
225
226    @Override
227    public void engineStore(OutputStream stream, char[] password)
228            throws IOException, NoSuchAlgorithmException, CertificateException {
229        if (stream == null) {
230            throw new IOException("store failed");
231        }
232
233        if (password == null) {
234            throw new NoSuchAlgorithmException();
235        } else if (password.length == 0) {
236            throw new CertificateException();
237        }
238    }
239
240    @Override
241    public void engineStore(LoadStoreParameter param) throws IOException,
242            NoSuchAlgorithmException, CertificateException {
243        if (param == null) {
244            throw new IOException();
245        }
246
247        ProtectionParameter pParam = param.getProtectionParameter();
248        if (pParam instanceof PasswordProtection) {
249            char[] password = ((PasswordProtection) pParam).getPassword();
250            if (password == null) {
251                throw new NoSuchAlgorithmException();
252            } else if (password.length == 0) {
253                throw new CertificateException();
254            }
255            return;
256        }
257        throw new UnsupportedOperationException();
258    }
259
260}
261