/*
* Demoiselle Framework
* Copyright (C) 2010 SERPRO
* ----------------------------------------------------------------------------
* This file is part of Demoiselle Framework.
*
* Demoiselle Framework is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License version 3
* as published by the Free Software Foundation.
*
* This program 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 Lesser General Public License version 3
* along with this program; if not, see <http://www.gnu.org/licenses/>
* or write to the Free Software Foundation, Inc., 51 Franklin Street,
* Fifth Floor, Boston, MA 02110-1301, USA.
* ----------------------------------------------------------------------------
* Este arquivo é parte do Framework Demoiselle.
*
* O Framework Demoiselle é um software livre; você pode redistribuí-lo e/ou
* modificá-lo dentro dos termos da GNU LGPL versão 3 como publicada pela Fundação
* do Software Livre (FSF).
*
* Este programa é distribuído na esperança que possa ser útil, mas SEM NENHUMA
* GARANTIA; sem uma garantia implícita de ADEQUAÇÃO a qualquer MERCADO ou
* APLICAÇÃO EM PARTICULAR. Veja a Licença Pública Geral GNU/LGPL em português
* para maiores detalhes.
*
* Você deve ter recebido uma cópia da GNU LGPL versão 3, sob o título
* "LICENCA.txt", junto com esse programa. Se não, acesse <http://www.gnu.org/licenses/>
* ou escreva para a Fundação do Software Livre (FSF) Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA.
*/
package br.gov.frameworkdemoiselle.certificate.extension;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.logging.Logger;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERIA5String;
import org.bouncycastle.asn1.DERObject;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.DERTaggedObject;
import org.bouncycastle.asn1.x509.AccessDescription;
import org.bouncycastle.asn1.x509.AuthorityInformationAccess;
import org.bouncycastle.asn1.x509.CRLDistPoint;
import org.bouncycastle.asn1.x509.DistributionPoint;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.PolicyInformation;
import org.bouncycastle.asn1.x509.X509Extensions;
import org.bouncycastle.x509.extension.X509ExtensionUtil;
/**
* Basic Information for ICP-BRASIL (DOC-ICP-04) Certificates. Abstracts the
* rules to PESSOA FISICA, PESSOA JURIDICA and EQUIPAMENTO/APLICAÇÃO
*
*
* @author CETEC/CTCTA
*/
public class BasicCertificate {
private static final Logger LOGGER = Logger.getLogger(BasicCertificate.class.getName());
public static final String OID_A1_CERTIFICATE = "2.16.76.1.2.1";
public static final String OID_A2_CERTIFICATE = "2.16.76.1.2.2";
public static final String OID_A3_CERTIFICATE = "2.16.76.1.2.3";
public static final String OID_A4_CERTIFICATE = "2.16.76.1.2.4";
public static final String OID_S1_CERTIFICATE = "2.16.76.1.2.101";
public static final String OID_S2_CERTIFICATE = "2.16.76.1.2.102";
public static final String OID_S3_CERTIFICATE = "2.16.76.1.2.103";
public static final String OID_S4_CERTIFICATE = "2.16.76.1.2.104";
private X509Certificate certificate = null;
private ICPBRSubjectAlternativeNames subjectAlternativeNames = null;
private ICPBRKeyUsage keyUsage = null;
private ICPBR_DN certificateFrom = null;
private ICPBR_DN certificateFor = null;
/**
* @param certificate -> type X509Certificate
* @see java.security.cert.X509Certificate
*/
public BasicCertificate(X509Certificate certificate) {
this.certificate = certificate;
}
/**
*
* @param data
* @throws Exception
*/
public BasicCertificate(byte[] data) throws Exception {
this.certificate = getCertificate(data);
}
/**
*
* @param is
* @throws Exception
* @throws IOException
*/
public BasicCertificate(InputStream is) throws IOException, Exception {
this.certificate = getCertificate(is);
}
/**
*
* @param is -> InputStream
* @return X509Certificate
* @throws CertificateException
* @throws IOException
* @throws Exception
*/
private X509Certificate getCertificate(InputStream is) throws CertificateException, IOException, Exception {
CertificateFactory cf = CertificateFactory.getInstance("X509");
X509Certificate cert = (X509Certificate) cf.generateCertificate(is);
return cert;
}
/**
*
* @param data -> byte array
* @return String
*/
private String toString(byte[] data) {
if (data == null) {
return null;
}
return toString(new BigInteger(1, data));
}
/**
*
* @param bi -> Big Integer
* @return String
*/
private String toString(BigInteger bi) {
if (bi == null) {
return null;
}
String ret = bi.toString(16);
if (ret.length() % 2 == 1) {
ret = "0" + ret;
}
return ret.toUpperCase();
}
/**
*
* @param data -> Byte Array
* @return X509Certificate
* @throws Exception
*/
private X509Certificate getCertificate(byte[] data) throws Exception {
ByteArrayInputStream bis = new ByteArrayInputStream(data);
X509Certificate cert = getCertificate(bis);
bis.close();
bis = null;
return cert;
}
/**
* Return the certificate on original format X509Certificate<br>
*
* @return X509Certificate
*/
public X509Certificate getX509Certificate() {
return certificate;
}
/**
* Returns the IssuerDn of certificate on ICPBR_DN format thats works as a
* properties<br>
*
* The toString Method of this class returns IssuerDn.getName()<br>
*
* @return ICPBR_DN
* @see ICPBR_DN
* @throws IOException
*/
public ICPBR_DN getCertificateIssuerDN() throws IOException {
if (certificateFrom == null) {
certificateFrom = new ICPBR_DN(certificate.getIssuerDN().getName());
}
return certificateFrom;
}
/**
* Returns the SerialNumber of certificate on String format<br>
*
* @return String
*/
public String getSerialNumber() {
return toString(certificate.getSerialNumber());
}
/**
* Returns the SubjectDN of certificate on ICPBR_DN on ICPBR_DN format thats
* works as a properties<br>
*
* The toString Method of this class returns SubjectDN.getName()<br>
*
* @return ICPBR_DN
* @see ICPBR_DN
* @throws IOException
*/
public ICPBR_DN getCertificateSubjectDN() throws IOException {
if (certificateFor == null) {
certificateFor = new ICPBR_DN(certificate.getSubjectDN().getName());
}
return certificateFor;
}
/**
* Returns the name that was defined on CN for CertificateSubjectDN.<br>
* Its similar to CertificateSubjectDN.getProperty("CN"), but ignoring<br>
* the information after ":".<br>
*
* @return String
*/
public String getNome() {
try {
String nome = this.getCertificateSubjectDN().getProperty("CN");
int pos;
pos = nome.indexOf(':');
if (pos > 0) {
return nome.substring(0, pos);
}
return nome;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
*
* @return Date -> Validate starts date
*/
public Date getBeforeDate() {
return certificate.getNotBefore();
}
/**
*
* @return Date -> Validate ends date
*/
public Date getAfterDate() {
return certificate.getNotAfter();
}
/**
* Returns the ICPBRKeyUsage Object with the informations about uses of the
* certificate<br>
*
* @return ICPBRKeyUsage
* @see ICPBRKeyUsage
*/
public ICPBRKeyUsage getICPBRKeyUsage() {
if (keyUsage == null) {
keyUsage = new ICPBRKeyUsage(certificate);
}
return keyUsage;
}
/**
* Returns the SubjectAlternativeNames of certificate in<br>
* ICPBRSubjectAlternativeNames format.<br>
* If not exists, returns <b>null</b>.<br>
*
* @return ICPBRSubjectAlternativeNames
* @see ICPBRSubjectAlternativeNames
*/
public ICPBRSubjectAlternativeNames getICPBRSubjectAlternativeNames() {
if (this.subjectAlternativeNames == null) {
this.subjectAlternativeNames = new ICPBRSubjectAlternativeNames(this.certificate);
}
return this.subjectAlternativeNames;
}
/**
* Returns the email address that was defined on
* SubjectAlternativeNames.<br>
* Similar getICPBRSubjectAlternativeNames().getEmail()<br>
* If not exists, returns <b>null</b>.<br>
*
* @return String
*/
public String getEmail() {
if (getICPBRSubjectAlternativeNames() == null) {
return null;
}
return getICPBRSubjectAlternativeNames().getEmail();
}
/**
* Check if the certificate has a "ICP-BRASIL Pessoa Fisica Certificate".
* DOC-ICP-04<br>
*
* @return boolean
*/
public boolean hasCertificatePF() {
if (getICPBRSubjectAlternativeNames() == null) {
return false;
}
return getICPBRSubjectAlternativeNames().isCertificatePF();
}
/**
* Returns data of "Pessoa Fisica" on certificate in ICPBRCertificatePF
* format<br>
* If its not a "Pessoa Fisica" certificate <br>
* Returns o valor <b>null</b>
*
* @return ICPBRCertificatePF
* @see ICPBRCertificatePF
*/
public ICPBRCertificatePF getICPBRCertificatePF() {
if (getICPBRSubjectAlternativeNames() == null) {
return null;
}
return getICPBRSubjectAlternativeNames().getICPBRCertificatePF();
}
/**
* * Check if the certificate has a "ICP-BRASIL Pessoa Juridica
* Certificate". DOC-ICP-04<br>
*
* @return boolean
*/
public boolean hasCertificatePJ() {
if (getICPBRSubjectAlternativeNames() == null) {
return false;
}
return getICPBRSubjectAlternativeNames().isCertificatePJ();
}
/**
* Returns data of "Pessoa Juridica" on certificate in ICPBRCertificatePJ
* format<br>
* If its not a "Pessoa Juridica" certificate <br>
* Returns o valor <b>null</b>
*
*
* @return ICPBRCertificatePJ
* @see ICPBRCertificatePJ
*/
public ICPBRCertificatePJ getICPBRCertificatePJ() {
if (getICPBRSubjectAlternativeNames() == null) {
return null;
}
return getICPBRSubjectAlternativeNames().getICPBRCertificatePJ();
}
/**
* Check if the certificate has a "ICP-BRASIL Equipment (Equipamento ou
* Aplicação) Certificate". DOC-ICP-04<br>
*
* @return boolean
*/
public boolean hasCertificateEquipment() {
if (getICPBRSubjectAlternativeNames() == null) {
return false;
}
return getICPBRSubjectAlternativeNames().isCertificateEquipment();
}
/**
* Returns data of "Equipamento/Aplicacao" on certificate in
* ICPBRCertificateEquipment format<br>
* If its not a "Equipamento/Aplicacao" certificate <br>
* Returns o valor <b>null</b>
*
*
* @return ICPBRCertificateEquipment
* @see ICPBRCertificateEquipment
*/
public ICPBRCertificateEquipment getICPBRCertificateEquipment() {
if (getICPBRSubjectAlternativeNames() == null) {
return null;
}
return getICPBRSubjectAlternativeNames().getICPBRCertificateEquipment();
}
/**
* Returns the PathLength value of Certificate BasicConstraint.<br>
* * <b>0</b> - if CA.<br>
* * <b>1</b> - for End User Certificate.<br>
*
* @return int
*/
public int getPathLength() {
return certificate.getBasicConstraints();
}
/**
* Check if is a Certificate Authority Certificate (ICP-BRASIL = AC).<br>
* * <b>true</b> - If CA.<br>
* * <b>false</b> -for End User Certificate.<br>
*
* @return boolean
*/
public boolean isCertificadoAc() {
return certificate.getBasicConstraints() >= 0;
}
/**
* returns the ICP-BRASIL Level Certificate(A1, A2, A3, A4, S1, S2, S3,
* S4).<br>
* DOC-ICP-04 Returns the <b>null</b> value if the CertificatePolicies is
* NOT present.
*
* @return String
*/
public String getNivelCertificado() {
try {
DERSequence seq = (DERSequence) getExtensionValue(X509Extensions.CertificatePolicies.getId());
if (seq == null) {
return null;
}
for (int pos = 0; pos < seq.size(); pos++) {
PolicyInformation policyInformation = new PolicyInformation((ASN1Sequence) seq.getObjectAt(pos));
String id = policyInformation.getPolicyIdentifier().getId();
if (id == null) {
continue;
}
if (id.startsWith(OID_A1_CERTIFICATE)) {
return "A1";
}
if (id.startsWith(OID_A2_CERTIFICATE)) {
return "A2";
}
if (id.startsWith(OID_A3_CERTIFICATE)) {
return "A3";
}
if (id.startsWith(OID_A4_CERTIFICATE)) {
return "A4";
}
if (id.startsWith(OID_S1_CERTIFICATE)) {
return "S1";
}
if (id.startsWith(OID_S2_CERTIFICATE)) {
return "S2";
}
if (id.startsWith(OID_S3_CERTIFICATE)) {
return "S3";
}
if (id.startsWith(OID_S4_CERTIFICATE)) {
return "S4";
}
}
return null;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* Returns the AuthorityKeyIdentifier extension value on String format.<br>
* Otherwise, returns <b>null</b>.<br>
*
* @return String
* @throws IOException
*/
public String getAuthorityKeyIdentifier() throws IOException {
// TODO - Precisa validar este metodo com a RFC
DERSequence seq = (DERSequence) getExtensionValue(X509Extensions.AuthorityKeyIdentifier.getId());
if (seq == null || seq.size() == 0) {
return null;
}
DERTaggedObject tag = (DERTaggedObject) seq.getObjectAt(0);
DEROctetString oct = (DEROctetString) DEROctetString.getInstance(tag);
return toString(oct.getOctets());
}
/**
* Returns the AuthorityInfoAccess extension value on list format.<br>
* Otherwise, returns <b>list empty</b>.<br>
* @return List
*/
public List<String> getAuthorityInfoAccess() {
List<String> address = new ArrayList<String>();
try {
byte[] extensionValue = certificate.getExtensionValue(X509Extensions.AuthorityInfoAccess.getId());
if (extensionValue != null && extensionValue.length > 0) {
AuthorityInformationAccess infoAccess = AuthorityInformationAccess.getInstance(X509ExtensionUtil
.fromExtensionValue(extensionValue));
for (AccessDescription desc : infoAccess.getAccessDescriptions())
if (desc.getAccessLocation().getTagNo() == GeneralName.uniformResourceIdentifier)
address.add(((DERIA5String) desc.getAccessLocation().getName()).getString());
}
return address;
} catch (IOException error) {
LOGGER.info(error.getMessage());
return address;
}
}
/**
* Returns the SubjectKeyIdentifier extension value on String format.<br>
* Otherwise, returns <b>null</b>.<br>
*
* @return String
* @throws java.io.IOException
*/
public String getSubjectKeyIdentifier() throws IOException {
// TODO - Precisa validar este metodo com a RFC
DEROctetString oct = (DEROctetString) getExtensionValue(X509Extensions.SubjectKeyIdentifier.getId());
if (oct == null) {
return null;
}
return toString(oct.getOctets());
}
/**
* Returns a List of URL for Certificate Revocation List. Must have on or
* more<br>
* Otherwise, returns <b>null</b>.<br>
*
* @return String
* @throws IOException
*/
public List<String> getCRLDistributionPoint() throws IOException {
List<String> lcrS = new ArrayList<String>();
DERObject derObj = getExtensionValue(X509Extensions.CRLDistributionPoints.getId());
if (derObj == null) {
return null;
}
CRLDistPoint crlDistPoint = CRLDistPoint.getInstance(derObj);
DistributionPoint[] dp = crlDistPoint.getDistributionPoints();
for (int i = 0; i < dp.length; i++) {
DERSequence seq = (DERSequence) new ASN1InputStream(dp[i].getDistributionPoint().getName().getDEREncoded()).readObject();
DERTaggedObject tag = (DERTaggedObject) seq.getObjectAt(0);
try {
ASN1OctetString oct = DEROctetString.getInstance(tag);
lcrS.add(new String(oct.getOctets()));
} catch (Exception e) {
// Não é um objeto com informação de DistributionPoint
}
}
return lcrS;
}
/**
* Returns the DERObject for the informed OID<br>
* atraves do OID.<br>
*
* @param oid
* @return DERObject
* @see DERObject
*/
public DERObject getExtensionValue(String oid) {
byte[] extvalue = certificate.getExtensionValue(oid);
if (extvalue == null) {
return null;
}
try {
DEROctetString oct = (DEROctetString) (new ASN1InputStream(extvalue).readObject());
return (new ASN1InputStream(oct.getOctets()).readObject());
} catch (IOException ex) {
LOGGER.info(ex.getMessage());
}
return null;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
try {
SimpleDateFormat dtValidade = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
builder.append("\n");
builder.append("-----------------------------------------\n");
builder.append("Certificado de..........[").append(this.getCertificateIssuerDN()).append("]\n");
builder.append("Serial Number...........[").append(this.getSerialNumber()).append("]\n");
builder.append("Certificado para........[").append(this.getCertificateSubjectDN()).append("]\n");
builder.append("Nome do Certif..........[").append(this.getNome()).append("]\n");
builder.append("Validade................[").append(dtValidade.format(this.getBeforeDate())).append(" ate ").append(dtValidade.format(this.getAfterDate())).append("]\n");
builder.append("Email...................[").append(this.getEmail()).append("]\n");
builder.append("-----------------------------------------\n");
builder.append("Tem dados PF............[").append(this.hasCertificatePF()).append("]\n");
if (this.hasCertificatePF()) {
ICPBRCertificatePF ippBRCertificatePF = this.getICPBRCertificatePF();
builder.append("CPF.....................[").append(ippBRCertificatePF.getCPF()).append("]\n");
builder.append("Data Nascimento.........[").append(ippBRCertificatePF.getDataNascimento()).append("]\n");
builder.append("PIS.....................[").append(ippBRCertificatePF.getNis()).append("]\n");
builder.append("RG......................[").append(ippBRCertificatePF.getRg()).append("]\n");
builder.append("Orgão RG................[").append(ippBRCertificatePF.getOrgaoExpedidorRg()).append("]\n");
builder.append("UF RG...................[").append(ippBRCertificatePF.getUfExpedidorRg()).append("]\n");
builder.append("CEI.....................[").append(ippBRCertificatePF.getCEI()).append("]\n");
builder.append("Titulo..................[").append(ippBRCertificatePF.getTituloEleitor()).append("]\n");
builder.append("Seção...................[").append(ippBRCertificatePF.getSecaoTituloEleitor()).append("]\n");
builder.append("Zona....................[").append(ippBRCertificatePF.getZonaTituloEleitor()).append("]\n");
builder.append("Municipio Titulo........[").append(ippBRCertificatePF.getMunicipioTituloEleitor()).append("]\n");
builder.append("UF Titulo...............[").append(ippBRCertificatePF.getUfTituloEleitor()).append("]\n");
}
builder.append("-----------------------------------------\n");
builder.append("Tem dados PJ............[").append(this.hasCertificatePF()).append("]\n");
if (this.hasCertificatePJ()) {
ICPBRCertificatePJ tdPJ = this.getICPBRCertificatePJ();
builder.append("CNPJ....................[").append(tdPJ.getCNPJ()).append("]\n");
builder.append("CEI.....................[").append(tdPJ.getCEI()).append("]\n");
builder.append("NIS.....................[").append(tdPJ.getNis()).append("]\n");
builder.append("Responsável.............[").append(tdPJ.getNomeResponsavel()).append("]\n");
}
builder.append("-----------------------------------------\n");
builder.append("Tem dados Equip.........:").append(this.hasCertificateEquipment()).append("]\n");
if (this.hasCertificateEquipment()) {
ICPBRCertificateEquipment tdEq = this.getICPBRCertificateEquipment();
builder.append("CNPJ....................[").append(tdEq.getCNPJ()).append("]\n");
builder.append("NIS.....................[").append(tdEq.getNis()).append("]\n");
builder.append("Nome Empresa............[").append(tdEq.getNomeEmpresarial()).append("]\n");
builder.append("Responsável.............[").append(tdEq.getNomeResponsavel()).append("]\n");
}
builder.append("-----------------------------------------\n");
builder.append("Eh CertificadoAC........[").append(this.isCertificadoAc()).append("]\n");
builder.append("PathLength..............[").append(this.getPathLength()).append("]\n");
builder.append("Tipo Certificado........[").append(this.getNivelCertificado()).append("]\n");
builder.append("Tipo de Uso.............[").append(this.getICPBRKeyUsage()).append("]\n");
builder.append("-----------------------------------------\n");
builder.append("Authority KeyID.........[").append(this.getAuthorityKeyIdentifier()).append("]\n");
builder.append("Authority Info Access...[").append(this.getAuthorityInfoAccess()).append("]\n");
builder.append("Subject KeyID...........[").append(this.getSubjectKeyIdentifier()).append("]\n");
builder.append("CRL DistPoint...........[").append(this.getCRLDistributionPoint()).append("]\n");
} catch (IOException ex) {
LOGGER.info(ex.getMessage());
}
return builder.toString();
}
}