source: trunk/seguranca/ExpressoCert/src/br/gov/serpro/cert/DigitalCertificate.java @ 1035

Revision 1035, 26.0 KB checked in by rafaelraymundo, 15 years ago (diff)

Ticket #558 - Adicionada funcionalidade de assinatura e criptografia de e-mails.

Line 
1package br.gov.serpro.cert;
2
3import br.gov.serpro.setup.Setup;
4import java.awt.Frame;
5import java.io.ByteArrayInputStream;
6import java.io.ByteArrayOutputStream;
7import java.io.File;
8import java.io.FileInputStream;
9import java.io.IOException;
10import java.io.InputStream;
11import java.net.MalformedURLException;
12import java.net.URL;
13import java.security.AuthProvider;
14import java.security.GeneralSecurityException;
15import java.security.Key;
16import java.security.KeyPair;
17import java.security.KeyStore;
18import java.security.KeyStoreException;
19import java.security.PrivateKey;
20import java.security.Provider;
21import java.security.ProviderException;
22import java.security.Security;
23import java.security.cert.CertStore;
24import java.security.cert.Certificate;
25import java.security.cert.CollectionCertStoreParameters;
26import java.security.cert.X509Certificate;
27import java.util.ArrayList;
28import java.util.Enumeration;
29import java.util.List;
30import java.util.Map;
31import java.util.Properties;
32
33import javax.crypto.Cipher;
34import javax.mail.Message;
35import javax.mail.MessagingException;
36import javax.mail.Session;
37import javax.mail.internet.MimeBodyPart;
38import javax.mail.internet.MimeMessage;
39import javax.mail.internet.MimeMultipart;
40import javax.net.ssl.SSLHandshakeException;
41import javax.security.auth.login.LoginException;
42
43import org.apache.commons.httpclient.HttpClient;
44import org.apache.commons.httpclient.HttpException;
45import org.apache.commons.httpclient.methods.PostMethod;
46import org.apache.commons.httpclient.protocol.Protocol;
47import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
48import org.bouncycastle.asn1.ASN1EncodableVector;
49import org.bouncycastle.asn1.cms.AttributeTable;
50import org.bouncycastle.asn1.smime.SMIMECapability;
51import org.bouncycastle.asn1.smime.SMIMECapabilityVector;
52import org.bouncycastle.mail.smime.SMIMEException;
53import org.bouncycastle.mail.smime.SMIMESignedGenerator;
54
55import br.gov.serpro.ui.DialogBuilder;
56import br.gov.serpro.util.Base64Utils;
57import com.sun.mail.util.BASE64DecoderStream;
58import java.security.AlgorithmParameters;
59import javax.mail.BodyPart;
60import org.bouncycastle.asn1.ASN1InputStream;
61import org.bouncycastle.asn1.DERObject;
62import org.bouncycastle.cms.CMSException;
63import org.bouncycastle.cms.RecipientId;
64import org.bouncycastle.cms.RecipientInformation;
65import org.bouncycastle.cms.RecipientInformationStore;
66import org.bouncycastle.mail.smime.SMIMEEnvelopedParser;
67import org.bouncycastle.mail.smime.SMIMEUtil;
68
69/**
70 * Classe que realiza todo o trabalho realizado com o certificado
71 * @author Mário César Kolling - mario.kolling@serpro.gov.br
72 */
73
74//TODO: Criar exceções para serem lançadas, entre elas DigitalCertificateNotLoaded
75//TODO: Adicionar setup
76
77public class DigitalCertificate {
78
79    private TokenCollection tokens;
80        private Certificate cert; // Certificado extraído da KeyStore. Pode ser nulo.
81        private KeyStore keyStore; // KeyStore que guarda o certificado do usuário. Pode ser nulo.
82
83        private Frame parentFrame;
84    private Setup setup;
85
86        // TODO: Transformar pkcs12Input em uma string ou URL com o caminho para a KeyStore pkcs12
87        private FileInputStream pkcs12Input; // stream da KeyStore pkcs12. Pode ser nulo.
88        private String providerName; // Nome do SecurityProvider pkcs11 carregado. Pode ser nulo.
89        private String hostAddress; // Endereço do host, onde a página principal do
90
91        private static final String HOME_SUBDIR; // Subdiretório dentro do diretório home do usuário. Dependente de SO.
92        private static final String EPASS_2000; // Caminho da biblioteca do token ePass2000. Dependente de SO.
93
94        private static final String CRLF = "\r\n"; // Separa campos na resposta do serviço de verificação de certificados
95        private static final String SUBJECT_ALTERNATIVE_NAME = "2.5.29.17"; // Não é mais utilizado.
96        private static final URL[] TRUST_STORES_URLS = new URL[3]; // URLs (file:/) das TrustStores, cacerts (jre),
97                                                                                                                           // trusted.certs e trusted.jssecerts (home do usuário)
98                                                               // Utilizadas para validação do certificado do servidor.
99        private static final String[] TRUST_STORES_PASSWORDS = null; // Senhas para cada uma das TrustStores,
100                                                                                                                                 // caso seja necessário.
101        private int keystoreStatus;
102        public static final int KEYSTORE_DETECTED = 0;
103        public static final int KEYSTORE_NOT_DETECTED = 1;
104        public static final int KEYSTORE_ALREADY_LOADED = 2;
105
106        /*
107         * Bloco estático que define os caminhos padrões da instalação da jre,
108         * do diretório home do usuário, e da biblioteca de sistema do token ePass2000,
109         * de acordo com o sistema operacional.
110         */
111        static {
112
113                Properties systemProperties = System.getProperties();
114        Map<String, String> env = System.getenv();
115
116                /* TODO: Testar a existência de vários drivers de dispositivos. Determinar qual deve ser utilizado
117                 * e guardar em uma property no subdiretório home do usuário.
118                 */
119
120                if (systemProperties.getProperty("os.name").equalsIgnoreCase("linux")){
121                        HOME_SUBDIR = "/.java/deployment/security";
122                        EPASS_2000 = "/usr/lib/libepsng_p11.so";
123                }
124                else {
125                        HOME_SUBDIR = "\\dados de aplicativos\\sun\\java\\deployment\\security";
126                        EPASS_2000 = System.getenv("SystemRoot")+"\\system32\\ngp11v211.dll";
127            //EPASS_2000 = System.getenv("ProgramFiles")+"\\Gemplus\\GemSafe Libraries\\BIN\\gclib.dll";
128                }
129
130                try {
131                        if (systemProperties.getProperty("os.name").equalsIgnoreCase("linux")){
132                                TRUST_STORES_URLS[0] = new File(systemProperties.getProperty("java.home")
133                                        + "/lib/security/cacerts").toURI().toURL();
134                                TRUST_STORES_URLS[1] = new File(systemProperties.getProperty("user.home")
135                                        + HOME_SUBDIR + "/trusted.certs").toURI().toURL();
136                                TRUST_STORES_URLS[2] = new File(systemProperties.getProperty("user.home")
137                                        + HOME_SUBDIR + "/trusted.jssecerts").toURI().toURL();
138                        } else {
139
140                                TRUST_STORES_URLS[0] = new File(systemProperties.getProperty("java.home") +
141                                                "\\lib\\security\\cacerts").toURI().toURL();
142                                TRUST_STORES_URLS[1] = new File(systemProperties.getProperty("user.home") +
143                                                HOME_SUBDIR + "\\trusted.certs").toURI().toURL();
144                                TRUST_STORES_URLS[2] = new File(systemProperties.getProperty("user.home") +
145                                                HOME_SUBDIR + "\\trusted.jssecerts").toURI().toURL();
146                        }
147
148
149                } catch (MalformedURLException e) {
150                        e.printStackTrace();
151                }
152        }
153
154        /**
155         *
156         */
157        public DigitalCertificate() {
158                this.hostAddress = null;
159                this.parentFrame = null;
160        }
161
162        /**
163         * Construtor da classe. Recebe a {@link URL} da página em que a Applet está incluída.
164         * @param pageAddress URL da página em que a Applet está incluída
165         */
166        private DigitalCertificate(URL pageAddress){
167                this.hostAddress = pageAddress.getHost();
168                this.parentFrame = null;
169        }
170
171        private DigitalCertificate(Frame parent){
172                this.hostAddress = null;
173                this.parentFrame = parent;
174        }
175
176
177    public DigitalCertificate(Frame parent, Setup setup){
178                this(parent);
179        this.setup = setup;
180        }
181
182    public DigitalCertificate(URL pageAddress, Setup setup){
183                this(pageAddress);
184        this.setup = setup;
185        }
186
187        /**
188         * Destrói a Applet, removendo o security provider inicializado se o atributo providerName
189         * for diferente de nulo.
190         */
191        public void destroy(){
192
193                AuthProvider ap = null;
194
195        if (this.setup.getParameter("debug").equalsIgnoreCase("true")){
196            System.out.println("logout no provider");
197        }
198                if (keyStore != null){
199                        ap = (AuthProvider) this.keyStore.getProvider();
200                }
201
202                if (ap != null){
203                        try {
204                                ap.logout();
205                        } catch (LoginException e) {
206                if (this.setup.getParameter("debug").equalsIgnoreCase("true")){
207                    e.printStackTrace();
208                }
209                        }
210                }
211
212                if (providerName != null){
213                        Security.removeProvider(providerName);
214                }
215
216                this.cert = null;
217                this.keyStore = null;
218                this.hostAddress = null;
219                this.pkcs12Input = null;
220                this.providerName = null;
221
222        }
223
224        /**
225          * Procura pelo token nos locais padrões (Por enquanto só suporta o token ePass200),
226          * senão procura por um certificado A1 em System.getProperties().getProperty("user.home") +
227          * HOME_SUBDIR  + "/trusted.clientcerts" e retorna um inteiro de acordo com resultado desta procura.
228          *
229          * @author     Mário César Kolling
230          * @return     Retorna um destes valores inteiros DigitalCertificate.KEYSTORE_DETECTED,
231          *             DigitalCertificate.KEYSTORE_ALREADY_LOADED ou DigitalCertificate.KEYSTORE_NOT_DETECTED
232          * @see        DigitalCertificate
233          */
234        public int init(){
235
236                // TODO: Usar dentro de um "loop" para testar outros modelos de tokens.
237        this.tokens = new TokenCollection(setup);
238                int interfaceType = DigitalCertificate.KEYSTORE_DETECTED;
239
240                try
241                {
242                        // Tenta abrir o Token padrï¿œo (ePass2000).
243                        loadKeyStore();
244
245                }
246                catch (Exception e1){
247
248                        Provider[] providers = Security.getProviders();
249            if (this.setup.getParameter("debug").equalsIgnoreCase("true")){
250                for (Provider provider: providers){
251                    System.out.println(provider.getInfo());
252                }
253
254                // Não conseguiu abrir o token (ePass2000).
255                System.out.println("Erro ao ler o token: " + e1.getMessage());
256            }
257
258                        try
259                        {
260                                // Tenta abrir a keyStore padrão
261                                // USER_HOME/deployment/security/trusted.clientcerts
262
263                                Properties props = System.getProperties();
264                                pkcs12Input = new FileInputStream(props.getProperty("user.home") +  HOME_SUBDIR  + "/trusted.clientcerts");
265
266                                // Se chegar aqui significa que arquivo de KeyStore existe.
267                                keyStore = KeyStore.getInstance("JKS");
268
269                        }
270                        catch (Exception ioe){
271                                // Não conseguiu abrir a KeyStore pkcs12
272                if (this.setup.getParameter("debug").equalsIgnoreCase("true")){
273                    System.out.println(ioe.getMessage());
274                }
275                        }
276                }
277
278
279                if (keyStore == null){
280                        // Não conseguiu inicializar a KeyStore. Mostra tela de login com usuário e senha.
281                        this.keystoreStatus = DigitalCertificate.KEYSTORE_NOT_DETECTED;
282                //} else if (keyStore.getType().equalsIgnoreCase("pkcs11")){
283                } else {
284                        // Usa certificado digital.
285                        try {
286                                // Testa se uma keystore já foi carregada previamente
287                                if (keyStore.getType().equalsIgnoreCase("pkcs11")){
288                                        keyStore.load(null, null);
289                                } else {
290                                        keyStore.load(pkcs12Input, null);
291                                }
292
293                                // Se chegou aqui KeyStore está liberada, mostrar tela de login sem pedir o pin.
294                                this.keystoreStatus = DigitalCertificate.KEYSTORE_ALREADY_LOADED;
295
296                        } catch (ProviderException e) {
297                                // Algum erro ocorreu, mostra  tela de login com usuário e senha.
298                                this.keystoreStatus = DigitalCertificate.KEYSTORE_NOT_DETECTED;
299                                if (this.setup.getParameter("debug").equalsIgnoreCase("true")){
300                    e.printStackTrace();
301                }
302                        } catch (IOException e){
303                                // KeyStore não está liberada, mostra tela de login com o pin.
304                if (this.setup.getParameter("debug").equalsIgnoreCase("true")){
305                    System.out.println(e.getMessage());
306                }
307                                this.keystoreStatus = DigitalCertificate.KEYSTORE_DETECTED;
308                        } catch (GeneralSecurityException e){
309                if (this.setup.getParameter("debug").equalsIgnoreCase("true")){
310                    e.printStackTrace();
311                }
312                        }
313                }
314
315                return keystoreStatus;
316
317        }
318
319        /**
320         * Usado para assinar digitalmente um e-mail.
321         * @param mime
322         * @return String vazia
323         */
324        public String signMail (Map<String, String> data) throws IOException, GeneralSecurityException, SMIMEException, MessagingException{
325
326                Key privateKey = null;
327                if (this.keystoreStatus == DigitalCertificate.KEYSTORE_DETECTED){
328                        String pin = DialogBuilder.showPinDialog(this.parentFrame, this.setup);
329                        if (pin != null){
330                                openKeyStore(pin.toCharArray());
331                                privateKey = this.keyStore.getKey(keyStore.aliases().nextElement(), pin.toCharArray());
332                        }
333                        else {
334                                return null;
335                        }
336                }
337        /*
338                else if (this.keystoreStatus == DigitalCertificate.KEYSTORE_ALREADY_LOADED){
339                                if (DialogBuilder.showPinNotNeededDialog(this.parentFrame)){
340                                        openKeyStore(null);
341                                        privateKey = this.keyStore.getKey(keyStore.aliases().nextElement(), null);
342                                }
343                                else {
344                                        return null;
345                                }
346                }
347         */
348                else {
349
350            //DialogBuilder.showMessageDialog(this.parentFrame, "Nenhum token/smartcard foi detectado.\nOperação não pôde ser realizada!");
351            DialogBuilder.showMessageDialog(this.parentFrame, setup.getLang("ExpressoCertMessages", "DigitalCertificate001"), this.setup);
352                        return null;
353                }
354
355                Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
356
357                Certificate certificate = getCert();
358
359                KeyPair keypair = new KeyPair(certificate.getPublicKey(), (PrivateKey) privateKey);
360
361                // Cria a cadeia de certificados que a gente vai enviar
362        List certList = new ArrayList();
363
364        certList.add(certificate);
365
366        //
367        // create the base for our message
368                //
369        String fullMsg = data.get("body");
370
371        if (this.setup.getParameter("debug").equalsIgnoreCase("true")){
372            System.out.println("Corpo do e-mail:\n"+fullMsg+"\n");
373        }
374       
375        //
376        // Get a Session object and create the mail message
377        //
378        Properties props = System.getProperties();
379        Session session = Session.getDefaultInstance(props, null);
380
381        InputStream is = new ByteArrayInputStream(fullMsg.getBytes("iso-8859-1"));
382                MimeMessage unsignedMessage = new MimeMessage(session, is);
383
384        //
385        // create a CertStore containing the certificates we want carried
386        // in the signature
387        //
388        if (this.setup.getParameter("debug").equalsIgnoreCase("true")){
389            System.out.println("Provider: " + providerName);
390        }
391        CertStore certsAndcrls = CertStore.getInstance(
392                                "Collection",
393                                new CollectionCertStoreParameters(certList), "BC");
394
395        //
396        // create some smime capabilities in case someone wants to respond
397        //
398        ASN1EncodableVector signedAttrs = new ASN1EncodableVector();
399
400        SMIMECapabilityVector       caps = new SMIMECapabilityVector();
401
402        caps.addCapability(SMIMECapability.dES_EDE3_CBC);
403        caps.addCapability(SMIMECapability.rC2_CBC, 128);
404        caps.addCapability(SMIMECapability.dES_CBC);
405
406                SMIMESignedGenerator gen = new SMIMESignedGenerator(unsignedMessage.getEncoding());
407
408                gen.addSigner(keypair.getPrivate(), (X509Certificate) certificate, SMIMESignedGenerator.DIGEST_SHA1, new AttributeTable(signedAttrs), null);
409
410                gen.addCertificatesAndCRLs(certsAndcrls);
411
412        //TODO: Extrair todos os headers de unsignedMessage
413
414                // Gera a assinatura
415                Object content = unsignedMessage.getContent();
416
417                //TODO: igualar unsignedMessage a null
418                //TODO: Pegar os headers do objeto que guardarï¿œ esses headers quando necessï¿œrio.
419
420                MimeMultipart mimeMultipartContent = null;
421                MimeBodyPart mimeBodyPartContent = new MimeBodyPart();
422
423                if (content.getClass().getName().contains("MimeMultipart")){
424                        mimeMultipartContent = (MimeMultipart) content;
425                }
426                else {
427                        is = new ByteArrayInputStream(content.toString().getBytes("iso-8859-1"));
428                        mimeBodyPartContent = new MimeBodyPart(is);
429                        mimeBodyPartContent.setHeader("Content-Type", unsignedMessage.getHeader("Content-Type", null)); //TODO: testar se valor existe
430                        is = null;
431                }
432                content = null;
433
434                MimeBodyPart msg = null;
435                if (mimeMultipartContent == null){
436                        msg = mimeBodyPartContent;
437                        mimeBodyPartContent = null;
438                }
439                else {
440                        msg = new MimeBodyPart();
441                        msg.setContent(mimeMultipartContent);
442                        mimeMultipartContent = null;
443                }
444
445        //
446        // extract the multipart object from the SMIMESigned object.
447        //
448        MimeMultipart mm = gen.generate(msg, providerName);
449        gen = null;
450        msg = null;
451
452        MimeMessage body = new MimeMessage(session);
453        body.setFrom(unsignedMessage.getFrom()[0]);
454        body.setRecipients(Message.RecipientType.TO, unsignedMessage.getRecipients(Message.RecipientType.TO));
455        body.setRecipients(Message.RecipientType.CC, unsignedMessage.getRecipients(Message.RecipientType.CC));
456        body.setRecipients(Message.RecipientType.BCC, unsignedMessage.getRecipients(Message.RecipientType.BCC));
457        body.setSubject(unsignedMessage.getSubject(), "iso-8859-1");
458
459        // Atrafuia o resto dos headers       
460        body.setHeader("Return-Path", unsignedMessage.getHeader("Return-Path", null));
461        body.setHeader("Message-ID", unsignedMessage.getHeader("Message-ID", null));
462        body.setHeader("X-Priority", unsignedMessage.getHeader("X-Priority", null));
463        body.setHeader("X-Mailer", unsignedMessage.getHeader("X-Mailer", null));
464        body.setHeader("Disposition-Notification-To", unsignedMessage.getHeader("Disposition-Notification-To", null));
465        body.setHeader("Date", unsignedMessage.getHeader("Date", null));
466        body.setContent(mm, mm.getContentType());
467        mm = null;
468
469        if (setup.getParameter("debug").equalsIgnoreCase("true")) {
470            System.out.println("\nHeaders do e-mail original:\n");
471        }
472
473        body.saveChanges();
474
475        ByteArrayOutputStream oStream = new ByteArrayOutputStream();
476       
477        oStream = new ByteArrayOutputStream();
478        body.writeTo(oStream);
479     
480        body = null;
481        return oStream.toString("iso-8859-1");
482
483        }
484   
485        /**
486         * Método utilizado para criptografar um e-mail
487         * @param source
488         * @return
489         */
490    public String cipherMail(Map<String, String> data) throws IOException, GeneralSecurityException, MessagingException, CMSException, SMIMEException{
491       
492        //Pega certificado do usuário.
493       
494        Key privateKey = null;
495                if (this.keystoreStatus == DigitalCertificate.KEYSTORE_DETECTED){
496                        String pin = DialogBuilder.showPinDialog(this.parentFrame, this.setup);
497                        if (pin != null){
498                                openKeyStore(pin.toCharArray());
499                                privateKey = this.keyStore.getKey(keyStore.aliases().nextElement(), pin.toCharArray());
500                        }
501                        else {
502                                return null;
503                        }
504                }
505        /*
506                else if (this.keystoreStatus == DigitalCertificate.KEYSTORE_ALREADY_LOADED){
507                                if (DialogBuilder.showPinNotNeededDialog(this.parentFrame)){
508                                        openKeyStore(null);
509                                        privateKey = this.keyStore.getKey(keyStore.aliases().nextElement(), null);
510                                }
511                                else {
512                                        return null;
513                                }
514                }
515         */
516                else {
517
518            //DialogBuilder.showMessageDialog(this.parentFrame, "Nenhum token/smartcard foi detectado.\nOperação não pôde ser realizada!");
519            DialogBuilder.showMessageDialog(this.parentFrame, setup.getLang("ExpressoCertMessages", "DigitalCertificate001"), this.setup);
520                        return null;
521                }
522
523                Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
524
525                X509Certificate cert = (X509Certificate)getCert();
526       
527        RecipientId recId = new RecipientId();
528        recId.setSerialNumber(cert.getSerialNumber());
529        recId.setIssuer(cert.getIssuerX500Principal());
530       
531        Properties props = System.getProperties();
532        Session session = Session.getDefaultInstance(props, null);
533       
534        String fullMsg = data.get("body");
535        InputStream is = new ByteArrayInputStream(fullMsg.getBytes("iso-8859-1"));
536        MimeMessage encriptedMsg = new MimeMessage(session, is);
537
538        Provider prov = Security.getProvider(providerName);
539        if (this.setup.getParameter("debug").equalsIgnoreCase("true")){
540            System.out.println("Serviços do provider "+providerName+ ":\n"+ prov.getInfo());
541            for (Provider.Service service: prov.getServices())
542                System.out.println(service.toString() + ": " + service.getAlgorithm());
543        }
544
545        if (setup.getParameter("debug").equalsIgnoreCase("true")) {
546            System.out.println("Email criptografado:\n" + fullMsg);
547        }
548
549        SMIMEEnvelopedParser m = new SMIMEEnvelopedParser(encriptedMsg);
550        if (setup.getParameter("debug").equalsIgnoreCase("true")) {
551            System.out.println("Algoritmo de encriptação: " + m.getEncryptionAlgOID());
552        }
553
554        AlgorithmParameters algParams = m.getEncryptionAlgorithmParameters("BC");
555        if (this.setup.getParameter("debug").equalsIgnoreCase("true")){
556            System.out.println("Parâmetros do algoritmo: " + algParams.toString());
557        }
558
559        RecipientInformationStore recipients = m.getRecipientInfos();
560        RecipientInformation recipient = recipients.get(recId);
561
562        if (recipient != null){
563            MimeBodyPart decriptedBodyPart = SMIMEUtil.toMimeBodyPart(recipient.getContentStream(privateKey, this.providerName));
564            encriptedMsg.setContent(decriptedBodyPart.getContent(), decriptedBodyPart.getContentType());
565            encriptedMsg.saveChanges();
566
567            ByteArrayOutputStream oStream = new ByteArrayOutputStream();
568            encriptedMsg.writeTo(oStream);
569            encriptedMsg = null;
570
571            return oStream.toString("iso-8859-1");
572        }
573        else {
574            //DialogBuilder.showMessageDialog(this.parentFrame, "Não é possível ler este e-mail com o Certificado Digital apresentado!\n" +
575            //        "Motivo: Este e-mail não foi cifrado com a chave pública deste Certificado Digital.");
576            DialogBuilder.showMessageDialog(this.parentFrame, setup.getLang("ExpressoCertMessages", "DigitalCertificate002"), this.setup);
577            return null;
578        }
579    }
580
581        /**
582         * Pega as credenciais de login do dono do certificado do serviço de verificação de certificados
583         * @param       pin                     pin para acessar o token
584         * @return      resposta        Array de Strings em que:
585         *                                              Indice 0: código de retorno;
586         *                                              Indice 1: username se código de retorno for 0, senão mensagem de erro;
587         *                                              Indice 2: senha decriptada se código de retorno for 0, senão não existe;
588         * @throws SSLHandshakeException
589         * @throws HttpException
590         * @throws IOException
591         * @throws GeneralSecurityException
592         */
593        public String[] getCredentials(String pin) throws SSLHandshakeException, HttpException, IOException, GeneralSecurityException{
594
595                String[] resposta = null;
596
597        if (this.setup.getParameter("debug").equalsIgnoreCase("true")){
598            System.out.println("Proxy Configurado no browser: " + System.getProperty("http.proxyHost")
599                    + ":" + System.getProperty("http.proxyPort"));
600        }
601
602                // Registra novo protocolo https, utilizando nova implementação de AuthSSLProtocolSocketFactory
603                Protocol.registerProtocol("https", new Protocol("https",
604                                (ProtocolSocketFactory) new AuthSSLProtocolSocketFactory(TRUST_STORES_URLS, TRUST_STORES_PASSWORDS, this.setup),
605                                443));
606
607                HttpClient httpclient = new HttpClient();
608                // Define um método post para o link do serviço de verificação de certificados
609        if (System.getProperty("http.proxyHost") != null && System.getProperty("http.proxyPort") != null){
610            httpclient.getHostConfiguration().setProxy(System.getProperty("http.proxyHost"),
611                    Integer.parseInt(System.getProperty("http.proxyPort")));
612        }
613                PostMethod httppost = new PostMethod("https://"+ hostAddress + "/seguranca/vercert.php");
614
615                try {
616                        // Adiciona parâmetro certificado no método post, executa o método, pega a resposta do servidor
617                        // como uma string com CRLF de separador entre os campos e gera um array de Strings
618                        httppost.addParameter("certificado", Base64Utils.der2pem(cert.getEncoded()));
619                        httpclient.executeMethod(httppost);
620                        resposta = httppost.getResponseBodyAsString().split(CRLF);
621
622                        if (resposta.length > 2){
623                                if (Integer.parseInt(resposta[0].trim()) == 0){
624                                        // Se código da resposta for zero, decripta a senha criptografada do usuário
625                                        resposta[2] = decriptPassword(resposta[2].trim(), pin);
626                                }
627                        }
628
629                } catch (IOException e){
630                        // Se for instância de SSLHandshakeException faz um cast para este tipo e lança a exceção novamente
631                        // Isto é usado para diferenciar o tipo de falha, para que a mensagem para o usuário seja mostrada de
632                        // acordo.
633                        if (e instanceof SSLHandshakeException){
634                                throw (SSLHandshakeException) e;
635                        }
636                        // senão lança novamente a exceção do tipo IOException
637                        throw e;
638                } finally {
639                        // fecha a conexão
640                        httppost.releaseConnection();
641                }
642
643                return resposta;
644        }
645
646        /**
647         * Decripta a senha criptografada
648         * @param encodedPassword senha criptografada e codificada em base64 para ser decriptada
649         * @param pin pin para acessar a KeyStore
650         * @return decodedPassword
651         * @throws GeneralSecurityException se algum problema ocorrer na decriptação da senha.
652         */
653        public String decriptPassword(String encodedPassword, String pin) throws GeneralSecurityException{
654
655                String decodedPassword = new String();
656
657                // Pega a chave privada do primeiro certificado armazenado na KeyStore
658                Enumeration<String> en = this.keyStore.aliases();
659                String certAlias = en.nextElement();
660                Key privateKey = this.keyStore.getKey(certAlias, pin.toCharArray());
661
662                // Inicializa os cipher com os parâmetros corretos para realizar a decriptação
663                Cipher dcipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
664                dcipher.init(Cipher.DECRYPT_MODE, privateKey);
665
666                // Decodifica a senha em base64 e a decripta
667                decodedPassword = new String(dcipher.doFinal(Base64Utils.base64Decode(encodedPassword)));
668
669                return decodedPassword.trim();
670
671        }
672
673        /**
674         * Carrega um novo SecurityProvider
675         * @param pkcs11Config Linha de configuração do SmartCard ou Token
676         * @throws KeyStoreException Quando não conseguir iniciar a KeyStore, ou a lib do Token
677         *                                                       ou Smartcard não foi encontrada, ou o usuário não inseriu o Token.
678         */
679        private void loadKeyStore() throws KeyStoreException{
680
681                //Provider pkcs11Provider = new sun.security.pkcs11.SunPKCS11(new ByteArrayInputStream(pkcs11Config.getBytes()));
682                //Security.addProvider(pkcs11Provider);
683                this.keyStore = KeyStore.getInstance("PKCS11");
684                this.providerName = keyStore.getProvider().getName();
685
686        }
687
688        /**
689         *  Abre a keystore passando o pin
690         *  @param pin pin para acessar o Token
691         */
692        public void openKeyStore(char[] pin) throws IOException{
693
694                try {
695
696                        if (this.keyStore.getType().equals("PKCS11")){
697                                this.keyStore.load(null, pin);
698                        }
699                        else {
700                                this.keyStore.load(this.pkcs12Input, pin);
701                        }
702
703                        this.cert = this.keyStore.getCertificate(this.keyStore.aliases().nextElement());
704
705                } catch (GeneralSecurityException e) {
706            if (this.setup.getParameter("debug").equalsIgnoreCase("true")){
707                e.printStackTrace();
708            }
709                }
710
711        }
712
713        /**
714         * @return the cert
715         */
716        Certificate getCert() {
717                return this.cert;
718        }
719
720        /**
721         * @param cert the cert to set
722         */
723        void setCert(Certificate cert) {
724                this.cert = cert;
725        }
726
727}
Note: See TracBrowser for help on using the repository browser.