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

Last change on this file was 8379cd8, checked in by Antonio Araujo Brett <aaraujo@…>, 11 years ago

Agregado encabezado de licencia a archivos fuentes.

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