Commit 48275373 authored by Alberto Inch's avatar Alberto Inch
Browse files

Basado en librería firmador estatal

parent 507909e0
Pipeline #247 canceled with stages
# Proyecto verificar_firma_documento
# compilar las dependencias del proyecto [FirmarArchivoLib, RevocationLib]
# Instalación de dependencias
El proyecto require java openjdk-8 y maven para instalarlos ejecutar
```
sudo apt-get install openjdk-8-jdk
sudo apt-get install maven
```
# Compilar las dependencias del proyecto [firmador_libreria]
Clonar el proyecto
git@gitlab.geo.gob.bo:bid/firma-digital.git
------------------------------------------------------------------------
Ingresar a la carpeta firma-digital/GestionToken/FirmarArchivoLib
Ejecutar
mvn clean install
resultado
==============
BUILD SUCCESS
==============
------------------------------------------------------------------------
Ingresar a la carpeta firma-digital/GestionToken/RevocacionLib
Ejecutar
```
GIT_SSL_NO_VERIFY=true git clone https://gitlab.softwarelibre.gob.bo/adsib/firmador_estatal/firmador-libreria.git
```
Ingresar a la carpeta firmador-libreria y ejecutar
```
mvn clean install
```
resultado
==============
```
BUILD SUCCESS
==============
```
# compilar proyecto verificar_firma_documento con maven
Clonar el proyecto
git@gitlab.geo.gob.bo:adsib/verificar_firma_documento.git
```
GIT_SSL_NO_VERIFY=true git clone https://gitlab.agetic.gob.bo/adsib/verificar_firma_documento2.git
```
Ingresar a la carpeta verificar_firma_documento
Ingresar a la carpeta verificar_firma_documento2
Ejecutar
```
mvn clean install
```
resultado
==============
```
BUILD SUCCESS
==============
```
# Deployar el war generado en el servidor tomcat
# Desplegar el war generado en el servidor tomcat
El war generado se encuentra en la carpeta 'target' del modulo 'verificar_firma_documento'
El war generado se encuentra en la carpeta 'target' del modulo 'verificar_firma_documento2'
verificar_firma_documento/target/valide.war
verificar_firma_documento2/target/valide.war
......@@ -67,33 +67,41 @@
<artifactId>commons-io</artifactId>
<version>${commons-io.version}</version>
</dependency>
<!-- Obtener los certificados del PDF -->
<dependency>
<groupId>adsib.gob.bo</groupId>
<artifactId>FirmarArchivoLib</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>adsib.gob.bo</groupId>
<artifactId>RevocationLib</artifactId>
<version>1.0.0</version>
<groupId>org.glassfish.jersey.bundles</groupId>
<artifactId>jaxrs-ri</artifactId>
<version>2.1</version>
</dependency>
<!-- Obtener los certificados del PDF -->
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>adsib.gob.bo</groupId>
<artifactId>TokenLib</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>javax.faces</groupId>
<artifactId>javax.faces-api</artifactId>
<version>2.2</version>
</dependency>
<!-- firmador_estatal -->
<dependency>
<groupId>bo.gob.softwarelibre.firmadorestatal</groupId>
<artifactId>firmadorlibreria</artifactId>
<version>1.0-SNAPSHOT</version>
<type>jar</type>
</dependency>
<!-- JSON -->
<dependency>
<groupId>org.codehaus.jettison</groupId>
<artifactId>jettison</artifactId>
<version>1.3.8</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-server</artifactId>
<version>1.9</version>
</dependency>
</dependencies>
<build>
<finalName>${nombre_contexto}</finalName>
......
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package bo.gob.adsib.valide.bl;
import adsib.gob.bo.firmararchivolib.error.FirmaArchivoException;
import adsib.gob.bo.firmararchivolib.util.FirmaPDF;
import adsib.gob.bo.revocacionlib.crl.CrlAdministrador;
import adsib.gob.bo.revocacionlib.crl.data.EstadoRevocacion;
import adsib.gob.bo.revocacionlib.util.UtilidadeDeCertificado;
import adsib.gob.bo.tokenlib.cert.Certificado;
import bo.gob.adsib.valide.vo.RespuestaValidacionVo;
import bo.gob.adsib.valide.vo.RespuestaValidarRebocadoCertificadoVo;
import bo.gob.adsib.valide.vo.ValidacionCertificadoVo;
import com.itextpdf.text.pdf.PdfReader;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PublicKey;
import java.security.Security;
import java.security.SignatureException;
import java.security.cert.CRLException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateNotYetValidException;
import java.security.cert.X509Certificate;
import java.util.Date;
import java.util.List;
import javax.faces.context.FacesContext;
import javax.naming.InvalidNameException;
import javax.naming.ldap.LdapName;
import javax.naming.ldap.Rdn;
import org.apache.commons.lang.time.DateFormatUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
/**
*
* @author merlo
*/
public class FirmaBl {
static {
Security.addProvider(new BouncyCastleProvider());
}
/**
* Valida las Firmas del Documento
*
* @param inputStream <code>InputStream</code> del Documento
* @return
* @throws IOException
* @throws URISyntaxException
* @throws CertificateException
* @throws NoSuchProviderException
* @throws CRLException
* @throws InvalidNameException
* @throws FirmaArchivoException
*/
public RespuestaValidacionVo validarArchivo(InputStream inputStream) throws IOException, URISyntaxException, CertificateException, NoSuchProviderException, CRLException, InvalidNameException, FirmaArchivoException, SignatureException, GeneralSecurityException {
RespuestaValidacionVo respuestaValidacion = new RespuestaValidacionVo();
boolean autenticidad = true;
boolean identidad = true;
if (inputStream != null) {
//obtenemos lista de certificados del PDF
PdfReader pdfReader = new PdfReader(inputStream);
FirmaPDF firmaPDF = new FirmaPDF();
List<Certificate> lista = firmaPDF.obtenerCertificados(pdfReader);
if (null != lista && lista.size() > 0) {
// cargando pk de la entidad raiz - para hacer la validacion de cadena de confianza
PublicKey publicKey = obtenerLlavePublica("/WEB-INF/clave_publica_adsib.pem");
/* validando identidad, autenticidad por certificado */
for (Certificate certificate : lista) {
//cargando crl
CrlAdministrador cm = null;
String msgCrlException = null;
try{
cm = obtenerCrlAdministrador((X509Certificate) certificate);
} catch (CRLException e) {
msgCrlException = e.getMessage();
}
//System.out.println("Certificado________________________________________");
//System.out.println(certificate);
//verificando identidad
ValidacionCertificadoVo validacionCertificadoVo = new ValidacionCertificadoVo();
boolean identidadCert = validarIdentidadCertificado(cm, publicKey, (X509Certificate) certificate, validacionCertificadoVo, msgCrlException);
if (!identidadCert) {
identidad = false;
}
//verificando autenticidad
boolean autenticidadCert = validarAutenticidad(pdfReader, (X509Certificate) certificate, validacionCertificadoVo);
if (!autenticidadCert) {
autenticidad = false;
}
if (identidadCert && autenticidadCert) {
validacionCertificadoVo.setPropietario(validacionCertificadoVo.getPropietario() + " - Firma válida");
validacionCertificadoVo.setValidacion(true);
} else {
validacionCertificadoVo.setPropietario(validacionCertificadoVo.getPropietario() + " - Firma no válida");
validacionCertificadoVo.setValidacion(false);
}
respuestaValidacion.getLista().add(validacionCertificadoVo);
}
pdfReader.close();
} else {
respuestaValidacion.setEstado("El documento no está firmado");
}
} else {
respuestaValidacion.setEstado("No se pudo enviar el documento");
}
return respuestaValidacion;
}
/* validaciones identidad */
/**
* Verifica la Identidad del Certificado (certificado valido) --cadena de
* confianza del Certificado --Vigencia del Certificado --Que el Certificado
* no haya sido Revocado
*
* @param fileInputStream
* @param respVal
*/
private boolean validarIdentidadCertificado(CrlAdministrador cm, PublicKey publicKey, X509Certificate cert, ValidacionCertificadoVo valCert, String msgCrlException) throws InvalidNameException {
valCert.setPropietario(getPropietarioCertificado(cert));
valCert.setCertificado(new Certificado(null, cert));
boolean res = true;
//verificar cadena de confianza
valCert.setCadenaConfianzaMsg("Cadena de confianza");
if (validarCadenaConfiansaCertificado(publicKey, cert)) {
valCert.setCadenaConfianza(true);
valCert.setCadenaConfianzaMsgDet("La cadena de confianza está bajo la Infraestructura de Clave Pública del Estado Plurinacional de Bolivia tiene valor legal");
} else {
res = false;
valCert.setCadenaConfianza(false);
valCert.setCadenaConfianzaMsgDet("La cadena de confianza no está bajo la Infraestructura de Clave Pública del Estado Plurinacional de Bolivia, y que por lo tanto no tiene valor legal");
}
//verificacion vigencia
valCert.setVigenciaMsgDet("Vigencia : desde "
+ DateFormatUtils.format(cert.getNotBefore(), "dd/MM/yyyy") + " hasta "
+ DateFormatUtils.format(cert.getNotAfter(), "dd/MM/yyyy"));
if (validarVigenciaCertificado(cert)) {
valCert.setVigencia(true);
valCert.setVigenciaMsg("Certificado vigente");
} else {
res = false;
valCert.setVigencia(false);
valCert.setVigenciaMsg("Certificado no vigente");
}
//verificacion de Revocacion
if (null != cm) {
RespuestaValidarRebocadoCertificadoVo respuestaValidarRebocadoCertificadoVo = validarRebocadoCertificado(cm, cert);
if (respuestaValidarRebocadoCertificadoVo.isRebocado()) {
valCert.setRevocado(true);
valCert.setRevocadoMsg("No revocado");
valCert.setRevocadoMsgDet("El certificado no esta revocado");
} else {
res = false;
valCert.setRevocado(false);
valCert.setRevocadoMsg("Revocado");
valCert.setRevocadoMsgDet(toStringEstadoRevocacion(respuestaValidarRebocadoCertificadoVo.getEstadoRevocacion()));
}
} else {
res = false;
valCert.setRevocadoMsg("Estado revocado");
valCert.setRevocadoMsgDet(msgCrlException);
}
return res;
}
/**
* Valida Cadena de confianza del Certificado
*
* @param publicKey
* @return
*/
private boolean validarCadenaConfiansaCertificado(PublicKey publicKey, X509Certificate cert) {
// Verificando
boolean esRamaAtt = true;
try {
cert.verify(publicKey, "BC");
} catch (CertificateException | NoSuchAlgorithmException | InvalidKeyException | NoSuchProviderException | SignatureException e) {
esRamaAtt = false;
e.printStackTrace();
}
return esRamaAtt;
}
/**
* Valida Vigencia del Certificado (vigencia realizada con la fecha actual)
*
* @param cert
* @return
*/
private boolean validarVigenciaCertificado(X509Certificate cert) {
boolean respuesta = false;
Date fechaActual = new Date();
try {
cert.checkValidity(fechaActual);
respuesta = true;
} catch (CertificateExpiredException | CertificateNotYetValidException e) {
//trace exception
}
return respuesta;
}
/**
* Valida si un certificado esta rebocado
*
* @param cm
* @param certificate
* @return
*/
private RespuestaValidarRebocadoCertificadoVo validarRebocadoCertificado(CrlAdministrador cm, X509Certificate certificate) {
RespuestaValidarRebocadoCertificadoVo respuestaValidarRebocadoCertificadoVo = new RespuestaValidarRebocadoCertificadoVo();
respuestaValidarRebocadoCertificadoVo.setRebocado(false);
respuestaValidarRebocadoCertificadoVo.setEstadoRevocacion(cm.estaRevocado(certificate.getSerialNumber()));
if (null == respuestaValidarRebocadoCertificadoVo.getEstadoRevocacion()) {
respuestaValidarRebocadoCertificadoVo.setRebocado(true);
}
return respuestaValidarRebocadoCertificadoVo;
}
/* end validacion identidad */
/* validaciones autenticidad */
/**
* Validacion del Autenticidad del Certificado
*
* @param pdfReader <code>PdfReader</code> del ImputStream
* @param cert Certificado <code>X509Certificate</code>
* @param valCert Objeto respuesta validacion certidficado
* @return
*/
private boolean validarAutenticidad(PdfReader pdfReader, X509Certificate cert, ValidacionCertificadoVo valCert) throws SignatureException, FirmaArchivoException, GeneralSecurityException {
boolean res = false;
FirmaPDF firmaPDF = new FirmaPDF();
boolean modificado = firmaPDF.estaModificadoElDocumento(pdfReader, cert);
if (modificado) {
valCert.setAutenticidad(false);
valCert.setAutenticidadMsg("El documento ha sido modificado");
valCert.setAutenticidadMsgDet("El documento ha sido modificado después de la firma");
} else {
res = true;
valCert.setAutenticidad(true);
valCert.setAutenticidadMsg("Documento auténtico");
valCert.setAutenticidadMsgDet("El documento no ha sido modificado después de la firma");
}
return res;
}
/**
* Obtine propietario de un Certificado - X509Certificate
*
* @param cert certificado <code>X509Certificate</code>
* @return
* @throws InvalidNameException
*/
private String getPropietarioCertificado(X509Certificate cert) throws InvalidNameException {
String subjectCN = "";
LdapName ldapDNSubject = new LdapName(cert.getSubjectDN().getName());
for (Rdn rdn : ldapDNSubject.getRdns()) {
if (rdn.getType().equals("CN")) {
subjectCN = String.valueOf(rdn.getValue());
break;
}
}
return subjectCN;
}
/**
* String del Objeto EstadoRevocacion
*
* @param estadoRevocacion
* @return
*/
private String toStringEstadoRevocacion(EstadoRevocacion estadoRevocacion) {
return estadoRevocacion.getDetalleRazonRevocacion();
}
/**
* Obtiene la llave publica desde una path
* path -> /WEB-INF/clave_publica_adsib.pemsudo apt-get install acroread
* @param ruta
* @return
* @throws FirmaArchivoException
*/
private PublicKey obtenerLlavePublica(String ruta) throws FirmaArchivoException {
InputStream is = FacesContext.getCurrentInstance().getExternalContext().getResourceAsStream(ruta);
FirmaPDF firmarPDF = new FirmaPDF();
PublicKey publicKey = firmarPDF.cargarClavePublica(is);
return publicKey;
}
/**
* Obtine CrlUrls de un certificado y crea un <code>CrlAdministrador</code>
* @param cert
* @return
*/
private CrlAdministrador obtenerCrlAdministrador(X509Certificate cert) throws CRLException {
//https://firmadigital.bo/firmadigital_bo.crl
CrlAdministrador cm = null;
try {
System.setProperty("com.sun.security.enableCRLDP", "true");
List<URL> strUris = UtilidadeDeCertificado.getCrlURLs(cert);
if(strUris != null && strUris.size() > 0) {
for (URL strUri : strUris) {
cm = new CrlAdministrador(strUri.toURI().toString());
}
} else {
throw new CRLException("Error interno al verificar el certificado por CRL u OCSP");
}
} catch (URISyntaxException | CRLException | CertificateException | NoSuchProviderException | NoSuchFieldError e) {
//trace exception
e.printStackTrace();
throw new CRLException("Error interno al verificar el certificado por CRL u OCSP");
}
return cm;
}
}
package bo.gob.adsib.valide.controller;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
/**
* Admitir certificados inválidos
* Extraido de https://stackoverflow.com/questions/33084855/way-to-ignore-ssl-certificate-using-httpsurlconnection
*/
public class HttpsTrustManager implements X509TrustManager {
private static TrustManager[] trustManagers;
private static final X509Certificate[] _AcceptedIssuers = new X509Certificate[]{};
@Override
public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException {
}
public boolean isClientTrusted(X509Certificate[] chain) {
return true;
}
public boolean isServerTrusted(X509Certificate[] chain) {
return true;
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return _AcceptedIssuers;
}
public static void allowAllSSL() {
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
SSLContext context = null;
if (trustManagers == null) {
trustManagers = new TrustManager[]{new HttpsTrustManager()};
}
try {
context = SSLContext.getInstance("TLS");
context.init(null, trustManagers, new SecureRandom());
} catch (NoSuchAlgorithmException | KeyManagementException e) {
e.printStackTrace();
}
HttpsURLConnection.setDefaultSSLSocketFactory(context != null ? context.getSocketFactory() : null);
}
}
......@@ -5,21 +5,21 @@
*/
package bo.gob.adsib.valide.controller;
import adsib.gob.bo.firmararchivolib.error.FirmaArchivoException;
import bo.gob.adsib.valide.bl.FirmaBl;
import bo.gob.adsib.valide.vo.RespuestaValidacionVo;
import bo.gob.adsib.valide.documento.Banderas;
import bo.gob.adsib.valide.documento.RespuestaValidacion;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.net.URISyntaxException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.security.GeneralSecurityException;
import java.security.NoSuchProviderException;
import java.security.SignatureException;
import java.security.cert.CRLException;
import java.security.cert.CertificateException;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.naming.InvalidNameException;
import org.apache.commons.io.FilenameUtils;
import org.primefaces.event.FileUploadEvent;
import org.primefaces.model.UploadedFile;
......@@ -32,10 +32,11 @@ import org.primefaces.model.UploadedFile;
@RequestScoped
public class ValidarFirmaController implements Serializable {
private RespuestaValidacionVo respuestaValidacion;
private RespuestaValidacion respuestaValidacion;
private String nombreArchivo;
private String respueta;
private Boolean mostrarRespuesta;
private String url;
private UploadedFile file;
......@@ -50,27 +51,168 @@ public class ValidarFirmaController implements Serializable {
*
* @param event
*/
public void validar(FileUploadEvent event) throws GeneralSecurityException {
respuestaValidacion = new RespuestaValidacionVo();
public void validar(FileUploadEvent event) {
UploadedFile archivo = event.getFile();
nombreArchivo = "Documento : " + archivo.getFileName();
if (nombreArchivo.toLowerCase().endsWith(".pdf")) {
try {
FirmaBl validarFirma = new FirmaBl();
respuestaValidacion = validarFirma.validarArchivo(archivo.getInputstream());
InputStream is = archivo.getInputstream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int read = 0;
while ((read = is.read(buffer, 0, buffer.length)) != -1) {
baos.write(buffer, 0, read);
}
baos.flush();
respuestaValidacion = new RespuestaValidacion(baos.toByteArray(), Banderas.TIPO_PDF, null);
if (respuestaValidacion.getLista().size() > 0) {
mostrarRespuesta = Boolean.TRUE;
}
} catch (Exception e) {