source: dispositivos_moviles/TibisayMovil/src/ve/gob/cenditel/tibisaymovil/DirectKeyChain.java @ bb739b0

Last change on this file since bb739b0 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: 14.8 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.Enumeration;
15
16
17import android.app.Activity;
18import android.content.Context;
19import android.content.DialogInterface;
20import android.net.Uri;
21import android.util.Log;
22import android.view.View;
23import android.view.ViewGroup;
24import android.widget.LinearLayout;
25import android.widget.ListView;
26import android.widget.TextView;
27import android.widget.Toast;
28
29public class DirectKeyChain { 
30
31    private static final long serialVersionUID = 5677500714263795351L;
32
33    private static final String keyStoreType = "BCPKCS12";
34    static final String keyStoreFilename = ".keystore";
35    private static KeyStore keystore = null;
36    private static String password = null;
37   
38
39        private static DirectKeyChain theInstance;
40
41        private Activity master;
42
43        private boolean buttonsKeyStoreStatus;
44
45        public boolean isButtonsKeyStoreStatus() {
46                return buttonsKeyStoreStatus;
47        }
48
49        public void setButtonsKeyStoreStatus(boolean buttonsKeyStoreStatus) {
50                this.buttonsKeyStoreStatus = buttonsKeyStoreStatus;
51        }
52
53
54        private ListView listView;
55
56        public DirectCertificateAdapter adapter;
57
58//      private MainBarClickListener mainbar;
59       
60        private DirectKeyChain() {
61        }
62       
63    private DirectKeyChain(Activity master) {
64        this.master=master;
65    }
66   
67    public void setMasterActivity(Activity master){this.master=master;}
68
69
70    public static DirectKeyChain getInstance() {
71
72        if (DirectKeyChain.theInstance == null) {
73
74                DirectKeyChain.theInstance = new DirectKeyChain();
75        }
76        return (DirectKeyChain) DirectKeyChain.theInstance;
77    }
78
79    public void choosePrivateKeyAlias() {
80
81        if (!keystoreExists()) {
82            createKeystoreAndChoosePrivateKeyAlias();
83        } else {
84            if (DirectKeyChain.keystore == null) {
85                openKeystoreAndChoosePrivateKeyAlias();
86            } else {
87                startKeyChainActivityAndChoosePrivateKeyAlias();
88            }
89        }
90     
91    }
92
93    public void openOrCreateKeyAlias() {
94
95      DirectKeyChain.keystore=null;
96      choosePrivateKeyAlias();
97       
98    }
99               
100    public X509Certificate[] getCertificateChain(String alias)
101    throws KeystoreException {
102
103        checkKeystoreOpen();
104        try {
105            KeyStore trusted = getKeystore();
106            Certificate[] chain = trusted.getCertificateChain(alias);
107            X509Certificate[] result = new X509Certificate[chain.length];
108            for(int i = 0; i < chain.length; i++) {
109                // Casting chain to X509Certificate[] seems to be not enough
110                result[i] = (X509Certificate) chain[i];
111            }
112            return result;
113        } catch (Exception e) {
114            throw new KeystoreException(e);
115        }
116    }
117
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        public int deleteCertificate(String alias) throws KeystoreException{
133               
134                try {
135                        KeyStore trusted = getKeystore();
136                trusted.deleteEntry(alias);
137                } catch (Exception e) {
138                        throw new KeystoreException(e);
139                }
140               
141                if (this.adapter!=null)this.adapter.notifyDataSetChanged();
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 = this.master.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(DirectKeyChain.password);
195    }
196
197    public void saveKeystore(String password)
198    throws KeystoreException, OutOfSpaceError {
199
200        try {
201            KeyStore trusted = getKeystore();
202            trusted.store(
203                    this.master.openFileOutput(DirectKeyChain.keyStoreFilename, Context.MODE_PRIVATE),
204                    password.toCharArray());
205            DirectKeyChain.password = password;
206        } catch (Exception e) {
207            FsUtils.checkOutOfSpace(e, false);
208            throw new KeystoreException(e);
209        }
210    }
211
212    private KeyStore newKeystore()
213    throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
214
215        DirectKeyChain.keystore = KeyStore.getInstance(DirectKeyChain.keyStoreType);
216        DirectKeyChain.keystore.load(null);
217        return DirectKeyChain.keystore;
218    }
219
220    private KeyStore getKeystore()
221    throws KeystoreException {
222
223        return getKeystore(DirectKeyChain.password);
224    }
225
226    private KeyStore getKeystore(String password)
227    throws KeystoreException {
228
229        if (DirectKeyChain.keystore == null) {
230            try {
231                if (keystoreExists()) {
232                    DirectKeyChain.keystore = KeyStore.getInstance(DirectKeyChain.keyStoreType);
233                    DirectKeyChain.keystore.load(this.master.openFileInput(
234                            DirectKeyChain.keyStoreFilename), password.toCharArray());
235                } else {
236                    newKeystore();
237                }
238                DirectKeyChain.password = password;
239            } catch (Exception e) {
240                                DirectKeyChain.password=null;
241                                DirectKeyChain.keystore=null;
242                if (IncorrectPasswordException.checkException(e)) {
243                   
244                    throw new IncorrectPasswordException(e);
245                }
246                throw new KeystoreException(e);
247            }
248        }
249       
250        return DirectKeyChain.keystore;
251    }
252   
253    private KeyStore reloadKeyStore(){
254        //TODO
255        if (DirectKeyChain.keystore!=null && DirectKeyChain.password!=null){
256                try {
257                                DirectKeyChain.keystore = KeyStore.getInstance(DirectKeyChain.keyStoreType);
258                                DirectKeyChain.keystore.load(this.master.openFileInput(
259                DirectKeyChain.keyStoreFilename), password.toCharArray());
260                } catch (KeyStoreException e) {}
261                  catch (CertificateException e) {}
262                          catch (FileNotFoundException e) {} 
263                  catch (NoSuchAlgorithmException e) {}
264                  catch (IOException e) {}             
265               
266               
267        }
268        else{}
269        return DirectKeyChain.keystore;
270
271    }
272   
273
274    private boolean keystoreExists() {
275
276        return this.master.getFileStreamPath(DirectKeyChain.keyStoreFilename).exists();
277    }
278
279    private void checkKeystoreOpen() throws KeystoreException {
280        if (DirectKeyChain.keystore == null) {
281            throw new KeystoreException("Neeed to open the keystore first");
282        }
283    }
284
285    public void createKeystoreAndChoosePrivateKeyAlias() {
286        final PasswordConfirmationDialog dialog =
287                new PasswordConfirmationDialog(this.master, R.string.keystore_create_password);
288        dialog.setAcceptListener(new DirectKeyChainAcceptListener(dialog, this.master));
289
290        dialog.show();
291    }
292   
293    private void openKeystoreAndChoosePrivateKeyAlias() {
294
295        final PasswordDialog dialog =
296                new PasswordDialog(this.master, R.string.keystore_password, true);
297        dialog.setAcceptListener(new DirectKeyChainOpenListener(dialog, this.master));
298        dialog.setRecreateListener(new DialogInterface.OnClickListener() {
299
300            @Override
301            public void onClick(DialogInterface dialog, int which) {
302                createKeystoreAndChoosePrivateKeyAlias();
303            }
304        });
305        dialog.show();
306    }
307   
308   
309   
310    private void startKeyChainActivityAndChoosePrivateKeyAlias() {
311       
312
313        if (DirectKeyChain.password==null)
314                this.choosePrivateKeyAlias();
315               
316                DirectKeyChain.this.refreshAdapter();
317        /*Intent intent = new Intent(this.master, KeyChainActivity.class);
318        this.master.startActivityForResult(intent, ActivityResult.PRIVATE_KEY_ALIAS);*/
319    }
320
321   
322   
323    public ListView getListView() {
324                return listView;
325        }
326
327        public void setListView(ListView listView) {
328                this.listView = listView;
329        }
330
331        public void refreshAdapter(){
332                       
333               
334                try {
335                        this.reloadKeyStore();
336                                this.adapter = new DirectCertificateAdapter(DirectKeyChain.this, this.master);
337                                this.getListView().setAdapter(DirectKeyChain.this.adapter);
338
339                        } catch (KeystoreException e) {
340                                //DirectKeyChain.password=null;
341                                //DirectKeyChain.keystore=null;
342                        }
343               
344                       
345        }
346
347
348        public class DirectKeyChainAcceptListener implements View.OnClickListener {
349       
350                private PasswordConfirmationDialog dialog;
351                private Context context;
352
353                public DirectKeyChainAcceptListener(PasswordConfirmationDialog dialog, Context context){
354                        this.dialog=dialog;
355                        this.context=context;
356                }
357
358        @Override
359        public void onClick(View v) {
360            String newPassword = dialog.getPassword();
361            dialog.dismiss();
362            try {
363   
364                DirectKeyChain.this.newKeystore();
365                DirectKeyChain.this.saveKeystore(newPassword);
366                DirectKeyChain.this.startKeyChainActivityAndChoosePrivateKeyAlias();
367
368                /******************** OJO********************/
369                // En este punto se muestran los elementos dentro del keystore
370                /*********************************************/
371                Log.i("DEBUG", "Mostrar elementos1");
372               
373               
374//              if (DirectKeyChain.this.mainbar!=null)
375//                        DirectKeyChain.this.mainbar.prepareDisplayedChild(1);
376            } catch (OutOfSpaceError e) {
377                Toast.makeText(DirectKeyChain.this.master, R.string.error_no_space, Toast.LENGTH_LONG).show();
378            } catch (Exception e) {
379                Toast.makeText(DirectKeyChain.this.master, R.string.error_unknown, Toast.LENGTH_LONG).show();
380               // throw new RuntimeException(e);
381            } 
382           
383            /*try {
384                                DirectKeyChain.this.getListView().setAdapter(new DirectCertificateAdapter(DirectKeyChain.this, this.context));
385                        } catch (KeystoreException e) {
386
387                        }*/
388            DirectKeyChain.this.refreshAdapter();
389        }
390    }
391   
392       
393        public class DirectKeyChainOpenListener implements View.OnClickListener {
394       
395                private PasswordDialog dialog;
396                private Context context;
397
398                public DirectKeyChainOpenListener(PasswordDialog dialog, Context context){
399                        this.dialog=dialog;
400                        this.context=context;
401                }
402               
403            @Override
404            public void onClick(View v) {
405                String password = dialog.getPassword();
406                boolean ok = false;
407                try {
408                    getKeystore(password);
409                    ok = true;
410                } catch (IncorrectPasswordException e) {
411                    ok = false;
412                                DirectKeyChain.password=null;
413                                //DirectKeyChain.keystore=null;
414                               
415                    dialog.retry();
416                } catch (KeystoreException e) {
417                    //throw new RuntimeException(e);
418                                DirectKeyChain.password=null;
419                                DirectKeyChain.keystore=null;
420                }
421                if (ok) {
422                        DirectKeyChain.this.buttonsKeyStoreStatus = true;
423                        Log.i("DEBUG", "Mostrar elementos2");
424                    dialog.dismiss();
425                    startKeyChainActivityAndChoosePrivateKeyAlias();
426                }
427               
428               
429               
430                /*try {
431                        if (DirectKeyChain.this.adapter==null){
432                                DirectKeyChain.this.adapter = new DirectCertificateAdapter(DirectKeyChain.this, this.context);
433                                        DirectKeyChain.this.getListView().setAdapter(DirectKeyChain.this.adapter);
434                        }
435                        else{
436                                DirectKeyChain.this.adapter.notifyDataSetChanged();
437                        }
438                        } catch (KeystoreException e) {
439
440                        }*/
441                DirectKeyChain.this.refreshAdapter();
442               
443            }
444        }
445       
446   
447    private static class PrivateKeyEnumeration implements Enumeration<String> {
448
449        private KeyStore keystore;
450        private Enumeration<String> aliases;
451        private String next;
452
453        public PrivateKeyEnumeration(KeyStore keystore) throws KeyStoreException {
454
455            this.keystore = keystore;
456            this.aliases = keystore.aliases();
457            this.next = lookForNextPrivateKeyAlias();
458        }
459
460        private String lookForNextPrivateKeyAlias() throws KeyStoreException {
461
462            while (this.aliases.hasMoreElements()) {
463                String alias = this.aliases.nextElement();
464                if (this.keystore.entryInstanceOf(alias, KeyStore.PrivateKeyEntry.class)) {
465                    return alias;
466                }
467            }
468            return null;
469        }
470
471        @Override
472        public boolean hasMoreElements() {
473
474            return this.next != null;
475        }
476
477        @Override
478        public String nextElement() {
479
480            String element = this.next;
481            try {
482                this.next = lookForNextPrivateKeyAlias();
483            } catch (KeyStoreException e) {
484                //throw new RuntimeException(e);
485            }
486            return element;
487        }
488    }
489
490
491        public boolean isPasswordCorrect() {
492                return (DirectKeyChain.password!=null);
493        }   
494}
Note: See TracBrowser for help on using the repository browser.