br.gov.jfrj.siga.cd.CertificadoUtil.java Source code

Java tutorial

Introduction

Here is the source code for br.gov.jfrj.siga.cd.CertificadoUtil.java

Source

/*******************************************************************************
 * Copyright (c) 2006 - 2011 SJRJ.
 * 
 *     This file is part of SIGA.
 * 
 *     SIGA is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 * 
 *     SIGA is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 * 
 *     You should have received a copy of the GNU General Public License
 *     along with SIGA.  If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************/
package br.gov.jfrj.siga.cd;

import java.io.IOException;
import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;

import javax.servlet.http.HttpServletRequest;

import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1String;
import org.bouncycastle.asn1.ASN1TaggedObject;
import org.bouncycastle.asn1.DLSequence;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.x509.extension.X509ExtensionUtil;

public class CertificadoUtil {

    /**
     * Interpreta um dado do tipo otherName. Obs. O JDK 5.0 no tem classes que
     * lidem com um dado do tipo OtherName.  necessrio usar o BouncyCastle.
     * 
     * @param encoded
     *            O dado em ASN.1.
     * @return Um par contendo o OID e o contedo.
     */
    public static Pair<ASN1ObjectIdentifier, String> getOtherName(DLSequence sequence) throws IOException {

        String conteudo = "";
        @SuppressWarnings("rawtypes")
        Enumeration en = sequence.getObjects();
        ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier) en.nextElement();
        ASN1TaggedObject taggedObject = (ASN1TaggedObject) en.nextElement();

        ASN1Primitive obj = taggedObject.getObject();
        if (obj instanceof ASN1String) { // Certificados antigos SERASA -
            // incorretos
            conteudo = ((ASN1String) obj).getString();
        } else if (obj instanceof ASN1OctetString) { // Certificados corretos
            conteudo = new String(((ASN1OctetString) obj).getOctets(), "ISO-8859-1");
        }

        return new Pair<ASN1ObjectIdentifier, String>(oid, conteudo);
    }

    /**
     * Recupera as propriedades ICP/Brasil-Pessoa Fsica (email e CPF)
     * 
     * @param cert
     * @return
     * @throws IOException
     * @throws CertificateParsingException
     */
    public static Properties recuperarPropriedadesNomesAlteranativos(X509Certificate cert)
            throws IOException, CertificateParsingException {
        Properties props = new Properties();
        Pair<ASN1ObjectIdentifier, String> otherName;

        Iterator<?> subjectAltNamesIt = X509ExtensionUtil.getSubjectAlternativeNames(cert).iterator();
        while (subjectAltNamesIt.hasNext()) {
            List<?> altName = (List<?>) subjectAltNamesIt.next();
            int type = ((Integer) altName.get(0)).intValue();
            if (type == GeneralName.rfc822Name) {
                String email = (String) altName.get(1);
                props.put("email", email);
            } else if (type == GeneralName.otherName) {
                otherName = getOtherName((DLSequence) altName.get(1));
                props.put(otherName.first.getId(), otherName.second);
            }
        }

        //      for (List<?> subjectAlternativeName : cert.getSubjectAlternativeNames()) {
        //         String email;
        //         @SuppressWarnings("unused")
        //         int pos;
        //
        //         // O primeiro elemento  um Integer com o valor 0 = otherName, 1
        //         // =
        //         // rfc822name etc.
        //         // O segundo valor  um byte array ou uma String. Veja o javadoc
        //         // de
        //         // getSubjectAlternativeNames.
        //         switch (((Number) subjectAlternativeName.get(0)).intValue()) {
        //         case 0: // OtherName - contm CPF, CNPJ etc.
        //            // o OID fica em otherName.first
        //            Collection collection = X509ExtensionUtil.getSubjectAlternativeNames(cert);
        //            otherName = getOtherName((byte[]) subjectAlternativeName.get(1));
        //            props.put(otherName.first.getId(), otherName.second);
        //            break;
        //         case 1: // rfc822Name - usado para email
        //            email = (String) subjectAlternativeName.get(1);
        //            props.put("email", email);
        //            break;
        //         default:
        //            break;
        //         }
        //      }
        return props;
    }

    /**
     * Recuperar o CPF de um certificado
     * 
     * @param cert
     * @return
     * @throws Exception
     */
    public static String recuperarCPF(X509Certificate cert) throws Exception {
        try {
            Properties props = recuperarPropriedadesNomesAlteranativos(cert);
            String sCPF = props.getProperty("2.16.76.1.3.1").substring(8, 19);

            @SuppressWarnings("unused")
            long lCPF = Long.valueOf(sCPF); // usado apenas para verificar se  numrico
            if (!isCPF(sCPF)) {
                throw new Exception("O CPF encontrado no  vlido!");
            }
            return sCPF;
        } catch (Exception e) {
            throw new Exception("No foi possvel obter o CPF :" + e.getMessage());
        }
    }

    /**
     * Verifica se o modo de autenticao do request  por certificado  
     * @param request
     * @return boolean
     */
    public static boolean isClientCertAuth(HttpServletRequest request) {
        return HttpServletRequest.CLIENT_CERT_AUTH.equals(request.getAuthType());
    }

    /**
     * Retorna o CPF a partir do certificado passado pelo request
     * 
     * @param request
     * @return
     * @throws Exception 
     */
    public static String recuperarCPF(HttpServletRequest request) throws Exception {
        X509Certificate[] certs = (X509Certificate[]) request.getAttribute("javax.servlet.request.X509Certificate");
        if (certs != null) {
            // varre a cadeia de certificados
            for (X509Certificate cert : certs) {
                try {
                    String cpf = CertificadoUtil.recuperarCPF(cert);
                    return cpf;
                } catch (Exception e) {
                    continue;
                }
            }
            throw new Exception("CPF no encontrado na cadeia de certificados fornecida!");
        } else {
            if ("https".equals(request.getScheme())) {
                throw new Exception("Este  um request HTTPS, mas nenhum certificado de cliente est disponvel!");
            } else {
                throw new Exception("Esta no  uma requisio HTTPS!");
            }
        }
    }

    /**
     * Verifica se o parmetro  um CPF vlido
     * 
     * @param cpf
     * @return
     */
    public static boolean isCPF(String cpf) {
        final int[] pesosCPF = { 11, 10, 9, 8, 7, 6, 5, 4, 3, 2 };
        if ((cpf == null) || (cpf.length() != 11))
            return false;
        Integer dig1 = obterDigito(cpf.substring(0, 9), pesosCPF);
        Integer dig2 = obterDigito(cpf.substring(0, 9) + dig1, pesosCPF);
        return cpf.equals(cpf.substring(0, 9) + dig1.toString() + dig2.toString());
    }

    /**
     * Clculo de dgito verificador auxiliar do clculo de CPF
     * 
     * @param str
     * @param pesos
     * @return
     */
    private static int obterDigito(String str, int[] pesos) {
        int sum = 0;
        for (int ind = str.length() - 1, digito; ind >= 0; ind--) {
            digito = Integer.parseInt(str.substring(ind, ind + 1));
            sum += digito * pesos[pesos.length - str.length() + ind];
        }
        sum = 11 - sum % 11;
        return sum > 9 ? 0 : sum;
    }

}