source: dispositivos_moviles/TibisayMovil/src/ve/gob/cenditel/tibisaymovil/CustomKeyChain.java @ 42e7061

Last change on this file since 42e7061 was 288126d, checked in by Jose Ruiz <joseruiz@…>, 11 years ago

Manejo de repositorio de certificados y firma con pkcs7

  • Property mode set to 100644
File size: 15.5 KB
Line 
1package ve.gob.cenditel.tibisaymovil;
2
3import java.io.FileNotFoundException;
4import java.io.IOException;
5import java.io.InputStream;
6import java.security.KeyStore;
7import java.security.KeyStore.PrivateKeyEntry;
8import java.security.KeyStoreException;
9import java.security.NoSuchAlgorithmException;
10import java.security.PrivateKey;
11import java.security.cert.Certificate;
12import java.security.cert.CertificateException;
13import java.security.cert.X509Certificate;
14import java.util.Collections;
15import java.util.Enumeration;
16import java.util.List;
17
18
19import android.content.Context;
20import android.content.DialogInterface;
21import android.content.Intent;
22import android.net.Uri;
23import android.view.View;
24import android.view.View.OnClickListener;
25import android.widget.Toast;
26
27public class CustomKeyChain extends KeyChainStrategy { 
28
29    private static final long serialVersionUID = 5677500714263795951L;
30
31    private static final String keyStoreType = "BCPKCS12";
32    private static final String keyStoreFilename = ".keystore";
33    private static KeyStore keystore = null;
34    private static String password = null;
35
36    private CustomKeyChain() {}
37
38    public static CustomKeyChain getInstance() {
39
40        if (KeyChainStrategy.theInstance == null) {
41
42            KeyChainStrategy.theInstance = new CustomKeyChain();
43        }
44        return (CustomKeyChain) KeyChainStrategy.theInstance;
45    }
46
47    @Override
48    public void choosePrivateKeyAlias() {
49       
50        this.keystore=null;
51
52        /*if (!keystoreExists()) {
53            createKeystoreAndChoosePrivateKeyAlias();
54        } else {*/
55            if (CustomKeyChain.keystore == null) {
56                openKeystoreAndChoosePrivateKeyAlias();
57            } else {
58                startKeyChainActivityAndChoosePrivateKeyAlias();
59            }
60        //}
61    }
62
63    //May not be used
64    @Override
65        public void choosePrivateKeyList() {
66 
67
68                if (!keystoreExists()) {
69                    createKeystoreToSelect();
70                } else {
71                    if (CustomKeyChain.keystore == null) {
72                        openKeystoreToSelect();
73                    } else {
74                        startKeyChainActivityToSelect();
75                    }
76                }
77            }           
78        @Override
79    public X509Certificate[] getCertificateChain(String alias)
80    throws KeystoreException {
81
82        checkKeystoreOpen();
83        try {
84            KeyStore trusted = getKeystore();
85            Certificate[] chain = trusted.getCertificateChain(alias);
86            X509Certificate[] result = new X509Certificate[chain.length];
87            for(int i = 0; i < chain.length; i++) {
88                // Casting chain to X509Certificate[] seems to be not enough
89                result[i] = (X509Certificate) chain[i];
90            }
91            return result;
92        } catch (Exception e) {
93            throw new KeystoreException(e);
94        }
95    }
96
97    @Override
98    public PrivateKey getPrivateKey(String alias)
99    throws KeystoreException {
100
101        checkKeystoreOpen();
102        try {
103            KeyStore trusted = getKeystore();
104            return ((PrivateKeyEntry) trusted.getEntry(alias, null)).getPrivateKey();
105        } catch (Exception e) {
106            throw new KeystoreException(e);
107        }
108    }
109   
110   
111   
112        @Override
113        public int deleteCertificate(String alias) throws KeystoreException{
114               
115                try {
116                        KeyStore trusted = getKeystore();
117                trusted.deleteEntry(alias);
118                } catch (Exception e) {
119                        throw new KeystoreException(e);
120                }
121               
122                return 0;
123               
124        }
125   
126   
127
128    public Enumeration<String> getAliases()
129    throws KeystoreException {
130
131        try {
132            KeyStore trusted = getKeystore();
133            return new PrivateKeyEnumeration(trusted);
134        } catch (KeyStoreException e) {
135            throw new KeystoreException(e);
136        }
137    }
138
139    public int importCertificate(Uri file, String password)
140    throws KeystoreException {
141
142        try {
143            KeyStore trusted = getKeystore();
144            KeyStore p12 = KeyStore.getInstance("PKCS12");
145            InputStream stream = KeyChainStrategy.activity.getContentResolver().openInputStream(file);
146            p12.load(stream, password.toCharArray());
147            stream.close();
148            Enumeration<String> aliases = p12.aliases();
149            int imported = 0;
150            while (aliases.hasMoreElements()) {
151                String alias = aliases.nextElement();
152                if (p12.isKeyEntry(alias)) {
153                    Certificate[] chain = p12.getCertificateChain(alias);
154                    for (Certificate cert : chain) {
155                        if (!(cert instanceof X509Certificate)) {
156                            throw new KeyStoreException();
157                        }
158                    }
159                    // TODO allow to import with a diferent alias. Warn if alias already exists
160                    trusted.setKeyEntry(alias, p12.getKey(alias, null), null, chain);
161                    imported++;
162                }
163            }
164            return imported;
165        } catch (Exception e) {
166            IncorrectPasswordException.checkException(e);
167            throw new KeystoreException(e);
168        }
169    }
170
171    public void saveKeystore()
172    throws KeystoreException, OutOfSpaceError {
173
174        saveKeystore(CustomKeyChain.password);
175    }
176
177    public void saveKeystore(String password)
178    throws KeystoreException, OutOfSpaceError {
179
180        try {
181            KeyStore trusted = getKeystore();
182            trusted.store(
183                    KeyChainStrategy.activity.openFileOutput(CustomKeyChain.keyStoreFilename, Context.MODE_PRIVATE),
184                    password.toCharArray());
185            CustomKeyChain.password = password;
186        } catch (Exception e) {
187            FsUtils.checkOutOfSpace(e, false);
188            throw new KeystoreException(e);
189        }
190    }
191   
192    public KeyStore reloadKeyStore(){
193        if (CustomKeyChain.keystore!=null && CustomKeyChain.password!=null){
194                try {
195                        CustomKeyChain.keystore = KeyStore.getInstance(CustomKeyChain.keyStoreType);
196                        CustomKeyChain.keystore.load(KeyChainStrategy.activity.openFileInput(
197                                        CustomKeyChain.keyStoreFilename), password.toCharArray());
198                } catch (KeyStoreException e) {}
199                  catch (CertificateException e) {}
200                          catch (FileNotFoundException e) {} 
201                  catch (NoSuchAlgorithmException e) {}
202                  catch (IOException e) {}             
203               
204               
205        }
206        return CustomKeyChain.keystore;
207
208    }
209   
210   
211   
212
213    private KeyStore newKeystore()
214    throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
215
216        CustomKeyChain.keystore = KeyStore.getInstance(CustomKeyChain.keyStoreType);
217        CustomKeyChain.keystore.load(null);
218        return CustomKeyChain.keystore;
219    }
220
221    private KeyStore getKeystore()
222    throws KeystoreException {
223
224        return getKeystore(CustomKeyChain.password);
225    }
226
227    private KeyStore getKeystore(String password)
228    throws KeystoreException {
229
230        if (CustomKeyChain.keystore == null) {
231            try {
232                if (keystoreExists()) {
233                    CustomKeyChain.keystore = KeyStore.getInstance(CustomKeyChain.keyStoreType);
234                    CustomKeyChain.keystore.load(KeyChainStrategy.activity.openFileInput(
235                            CustomKeyChain.keyStoreFilename), password.toCharArray());
236                } else {
237                    newKeystore();
238                }
239                CustomKeyChain.password = password;
240            } catch (Exception e) {
241                if (IncorrectPasswordException.checkException(e)) {
242                    CustomKeyChain.keystore = null;
243                    throw new IncorrectPasswordException(e);
244                }
245                throw new KeystoreException(e);
246            }
247        }
248        return CustomKeyChain.keystore;
249    }
250
251    private boolean keystoreExists() {
252
253        return KeyChainStrategy.activity.getFileStreamPath(CustomKeyChain.keyStoreFilename).exists();
254    }
255
256    private void checkKeystoreOpen() throws KeystoreException {
257        if (CustomKeyChain.keystore == null) {
258            throw new KeystoreException("Neeed to open the keystore first");
259        }
260    }
261
262    private void createKeystoreAndChoosePrivateKeyAlias() {
263        Toast.makeText(CustomKeyChain.activity, "createKeystoreAndChoosePrivateKeyAliasCustom", Toast.LENGTH_LONG).show();
264
265        final PasswordConfirmationDialog dialog =
266                new PasswordConfirmationDialog(KeyChainStrategy.activity, R.string.keystore_create_password);
267        dialog.setAcceptListener(new OnClickListener() {
268
269            @Override
270            public void onClick(View v) {
271                String newPassword = dialog.getPassword();
272                dialog.dismiss();
273                try {
274                    newKeystore();
275                    saveKeystore(newPassword);
276                    startKeyChainActivityAndChoosePrivateKeyAlias();
277                } catch (OutOfSpaceError e) {
278                    Toast.makeText(KeyChainStrategy.activity, R.string.error_no_space, Toast.LENGTH_LONG).show();
279                } catch (Exception e) {
280                    //throw new RuntimeException(e);
281                    Toast.makeText(KeyChainStrategy.activity, R.string.error_unknown, Toast.LENGTH_LONG).show();
282
283                }
284            }
285        });
286        dialog.show();
287    }
288   
289    private void openKeystoreAndChoosePrivateKeyAlias() {
290        Toast.makeText(CustomKeyChain.activity, "openKeystoreAndChoosePrivateKeyAlias", Toast.LENGTH_LONG).show();
291                //TODO: Setting boolean to false instead of true. Disables "New KeyStore" option.
292        final PasswordDialog dialog =
293                new PasswordDialog(KeyChainStrategy.activity, R.string.keystore_password, false);
294        dialog.setAcceptListener(new OnClickListener() {
295
296            @Override
297            public void onClick(View v) {
298
299                String password = dialog.getPassword();
300                boolean ok = false;
301                try {
302                    getKeystore(password);
303                    ok = true;
304                   
305                } catch (IncorrectPasswordException e) {
306                    ok = false;
307                    dialog.retry();
308                } catch (KeystoreException e) {
309                    Toast.makeText(KeyChainStrategy.activity, R.string.error_unknown, Toast.LENGTH_LONG).show();
310                    //throw new RuntimeException(e);
311                }
312                if (ok) {
313                        //Error #75046. No certificates installed.
314                        try {
315                                               
316                                List<String> aliases = Collections.list(CustomKeyChain.this.getAliases());
317                                if (aliases.size()>0){
318                                        dialog.dismiss();
319                                        startKeyChainActivityAndChoosePrivateKeyAlias();
320                                }else{
321                                    Toast.makeText(KeyChainStrategy.activity, R.string.error_empty_or_null_certificates, Toast.LENGTH_LONG).show();
322
323                                }
324                                        } catch (KeystoreException e) {
325                                        }
326 
327                }
328            }
329        });
330        dialog.setRecreateListener(new DialogInterface.OnClickListener() {
331
332            @Override
333            public void onClick(DialogInterface dialog, int which) {
334
335                createKeystoreAndChoosePrivateKeyAlias();
336            }
337        });
338        dialog.show();
339    }
340   
341   
342   
343    private void startKeyChainActivityAndChoosePrivateKeyAlias() {
344        Toast.makeText(CustomKeyChain.activity, "startKeyChainActivityAndChoosePrivateKeyAlias", Toast.LENGTH_LONG).show();
345
346        Intent intent = new Intent(KeyChainStrategy.activity, KeyChainActivity.class);
347        KeyChainStrategy.activity.startActivityForResult(intent, ActivityResult.PRIVATE_KEY_ALIAS);
348    }
349
350    private void startKeyChainActivityToSelect() {
351       
352            Intent intent = new Intent(KeyChainStrategy.activity, CertificateRepositoryActivity.class);
353       
354            KeyChainStrategy.activity.startActivityForResult(intent, ActivityResult.PRIVATE_KEY_ALIAS);         
355        }
356
357        private void createKeystoreToSelect() {
358        Toast.makeText(CustomKeyChain.activity, "createKeystoreToSelect", Toast.LENGTH_LONG).show();
359            final PasswordConfirmationDialog dialog =
360                    new PasswordConfirmationDialog(KeyChainStrategy.activity, R.string.keystore_create_password);
361            dialog.setAcceptListener(new OnClickListener() {
362       
363                @Override
364                public void onClick(View v) {
365                    String newPassword = dialog.getPassword();
366                    dialog.dismiss();
367                    try {
368                        newKeystore();
369                        saveKeystore(newPassword);
370                        startKeyChainActivityToSelect();
371                    } catch (OutOfSpaceError e) {
372                        Toast.makeText(KeyChainStrategy.activity, R.string.error_no_space, Toast.LENGTH_LONG).show();
373                    } catch (Exception e) {
374                    Toast.makeText(KeyChainStrategy.activity, R.string.error_unknown, Toast.LENGTH_LONG).show();
375                       // throw new RuntimeException(e);
376                    }
377                }
378            });
379            dialog.show();
380        }
381
382        private void openKeystoreToSelect() {
383        Toast.makeText(CustomKeyChain.activity, "openKeystoreToSelect", Toast.LENGTH_LONG).show();
384                //TODO: Setting boolean to false instead of true. Disables "New KeyStore" option.
385            final PasswordDialog dialog =
386                    new PasswordDialog(KeyChainStrategy.activity, R.string.keystore_password, false);
387            dialog.setAcceptListener(new OnClickListener() {
388       
389                @Override
390                public void onClick(View v) {
391       
392                    String password = dialog.getPassword();
393                    boolean ok;
394                    try {
395                        getKeystore(password);
396                        ok = true;
397                    } catch (IncorrectPasswordException e) {
398                        ok = false;
399                        dialog.retry();
400                    } catch (KeystoreException e) {
401                    Toast.makeText(KeyChainStrategy.activity, R.string.error_unknown, Toast.LENGTH_LONG).show();
402                        //throw new RuntimeException(e);
403                    ok = false;
404                    }
405                    if (ok) {
406                        dialog.dismiss();
407                        startKeyChainActivityToSelect();
408                    }
409                }
410            });
411            dialog.setRecreateListener(new DialogInterface.OnClickListener() {
412       
413                @Override
414                public void onClick(DialogInterface dialog, int which) {
415       
416                    createKeystoreToSelect();
417                }
418            });
419            dialog.show();
420        }
421
422        private static class PrivateKeyEnumeration implements Enumeration<String> {
423
424        private KeyStore keystore;
425        private Enumeration<String> aliases;
426        private String next;
427
428        public PrivateKeyEnumeration(KeyStore keystore) throws KeyStoreException {
429
430            this.keystore = keystore;
431            this.aliases = keystore.aliases();
432            this.next = lookForNextPrivateKeyAlias();
433        }
434
435        private String lookForNextPrivateKeyAlias() throws KeyStoreException {
436
437            while (this.aliases.hasMoreElements()) {
438                String alias = this.aliases.nextElement();
439                if (this.keystore.entryInstanceOf(alias, KeyStore.PrivateKeyEntry.class)) {
440                    return alias;
441                }
442            }
443            return null;
444        }
445
446        @Override
447        public boolean hasMoreElements() {
448
449            return this.next != null;
450        }
451
452        @Override
453        public String nextElement() {
454
455            String element = this.next;
456            try {
457                this.next = lookForNextPrivateKeyAlias();
458            } catch (KeyStoreException e) {
459                Toast.makeText(KeyChainStrategy.activity, R.string.error_unknown, Toast.LENGTH_LONG).show();
460
461                //throw new RuntimeException(e);
462            }
463            return element;
464        }
465    }
466   
467   
468}
Note: See TracBrowser for help on using the repository browser.