You are on page 1of 4

En este artículo se describen las acciones que se deben llevar a cabo para configurar un servidor

Apache-Tomcat 6.0 con autenticación mutua sobre SSL. Para llevar a cabo la autenticación mutua,
el servidor debe disponer de un certificado que lo acredite frente a los clientes que pretendan
establecer una conexión y además el propio servidor requiere un certificado válido al cliente, este
último certificado será el certificado de autenticación del DNIe. A continuación se detalla la
configuración que se ha de llevar a cabo.

Configuración del servidor Apache-Tomcat


Para habilitar las conexiones basadas en SSL en el servidor se debe modificar la configuración del
mismo.
Acceder al fichero de configuración del servidor Apache-Tomcat: server.xml. Este fichero
habitualmente se encuentra en la ruta $CATALINA_HOME/conf/server.xml, donde
$CATALINA_HOME es el directorio base del servidor, es decir, donde se ha instalado.
Se ha de editar el fichero de configuración añadiendo un conector a la configuración del servidor.
En este conector se especifican los siguientes atributos para que el servidor requiera autenticación
mutua sobre SSL:
• clientauth: Se le indica al servidor si tiene que requerir autenticación del usuario.
• keystorefile: Se indica el contenedor de claves que contiene las claves del certificado
del servidor.
• truststorefile: Se indica el contenedor de claves que contiene las claves del
certificado de la Autoridad de Certificación del DNIe.
• port: Se utiliza el puerto 8443 para el tráfico SSL.
A continuación se muestra la especificación del conector:
%%connector port="8443" protocol="HTTP/1.1" sslenabled="true" maxthreads="150"
scheme="https" secure="true" clientauth="true" sslprotocol="TLS"
keystorefile="certs/keystore.jks" keystorepass="inteco"
truststorefile="certs/ca_dnie.truststore" truststorepass="inteco"> %%/connector

Nota: Se ha de tener en cuenta que las rutas de keystorefile y truststorefile son


relativas al directorio base del servidor Tomcat, es decir, las rutas absolutas serían
$CATALINA_HOME/certs/a.jks y $CATALINA_HOME/certs/.truststore
respectivamente.

Creación de los almacenes de claves


Para la creación de los almacenes de claves Java es necesario hacer uso de la herramienta
keytool. Esta aplicación se incluye a partir de la versión JDK 1.6 . La ruta del comando
keytool es $JAVA_HOME/jre/bin/, donde la variable $JAVA_HOME es el directorio en el
que se encuentra el JDK.

Almacén de claves del Servidor


Para crear un contenedor de claves Java autogenerado del servidor (keystore.jks) se debe de
ejecutar el siguiente comando:
$>keytool -genkey -alias tomcat -keyalg RSA -keystore keystore.jks
Almacén de claves de la Autoridad de Certificación del DNIe
Para que el usuario pueda llevar a cabo la autenticación mediante DNIe en el servidor que se está
configurando, es necesario que el servidor disponga del certificado de la CA del DNIe .
Este certificado está en formato DER y el servidor Apache Tomcat espera un certificado en formato
PEM, por lo tanto, se tiene que realizar una conversión del formato del certificado. Para ello se
puede hacer uso la herramienta openssl tal y como se muestra a continuación:
#> openssl x509 -in ac_raiz_dnie.crt -inform DER -out ac_raiz_dnie.crt -outform
PEM

Una vez obtenido el certificado de la CA del DNIe en formato PEM, se ha de obtener el almacén de
claves del mismo para que el servidor lo utilice en el proceso de autenticación de usuarios mediante
DNIe. Para ello se utiliza de la herramienta herramienta keytool:
#> keytool -import -keystore ca_dnie.truststore -file ac_raiz_dnie.crt

Una vez llevadas a cabo las acciones anteriores, se ha de reiniciar el servidor Apache Tomcat. Para
probar que la configuración sobre SSL es correcta se debe abrir el siguiente enlace en el explorador
web:
https://localhost:8443/

Aplicación Web de prueba


Esta es una sencilla aplicación web implementada en Java mediante el IDE NetBeans que
consiste en la validación OCSP del certificado del DNIe del cliente que se conecte a la aplicación.
La comunicación cliente-servidor se lleva a cabo mediante SSL, para ello el servidor se ha
configurado tal y como se ha descrito en el punto anterior.
La aplicación consite en un fichero con extensión .JSP llamado index.jsp, que muestra la
información, y una clase llamada OCSP.

Fichero index.jsp
En el fichero index.jsp se lleva a cabo la carga de los certificados del cliente que se ha
conectado a la aplicación web. Siempre existirá algún certificado porque el servidor está
configurado para que la autenticación del cliente se lleve a cabo mediante certificado. Una vez
obtenido este certificado, se debe verificar su validez, en este caso se comprueba mediante el
servicio OCSP del DNIe.
##
OCSP ocsp = new OCSP();
X509Certificate[] certs = (X509Certificate[])
request.getAttribute("javax.servlet.request.X509Certificate");
if (certs != null)
out.println(ocsp.OCSP_validation(certs[0])); /*El primer certificado es el
de Autenticación en el caso del DNIe*/
!##

Clase OCSP
En la clase OCSP se define el método OCSP_validation()cuyo propósito es el de verificar la
validez de un certificado X.509 a través de un servicio remoto de validación de certificados del
DNIe. En concreto el servicio en el que se basa es http://ocsp.dnie.es . Para realizar este ejemplo,
se utilizan las librerías de código abierto Bouncy Castle . Estas librerías proporcionan una API
con todo tipo de funciones relacionadas con la seguridad computacional.

/* Se carga el proveedor necesario para la petición OCSP */


Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
InputStream inStreamIssuer1 = new
FileInputStream("/home/inteco/apache-tomcat-6.0.20/certs/ACDNIE001-SHA1.crt");
X509Certificate certImportadoIssuer1 = null;
InputStream inStreamIssuer2 = new
FileInputStream("/home/inteco/apache-tomcat-6.0.20/certs/ACDNIE002-SHA1.crt");
X509Certificate certImportadoIssuer2 = null;
InputStream inStreamIssuer3 = new
FileInputStream("/home/inteco/apache-tomcat-6.0.20/certs/ACDNIE003-SHA1.crt");
X509Certificate certImportadoIssuer3 = null;
X509Certificate certImportadoIssuer = null;
try {

/*Se extrae el nombre de la entidad emisora del certificado del DNIe*/


String issuerCN = certUsuario.getIssuerX500Principal().getName("CANONICAL");
CertificateFactory cfIssuer = CertificateFactory.getInstance("X.509");
/*En la validación OCSP se tendrá que usar el certificado de la CA subordinada
que emitió el certificado*/
if (issuerCN.contains("cn=ac dnie 001")) {
certImportadoIssuer = (X509Certificate)
cfIssuer.generateCertificate(inStreamIssuer1);
} else if (issuerCN.contains("cn=ac dnie 002")) {
certImportadoIssuer = (X509Certificate)
cfIssuer.generateCertificate(inStreamIssuer2);
} else if (issuerCN.contains("cn=ac dnie 003")) {
certImportadoIssuer = (X509Certificate)
cfIssuer.generateCertificate(inStreamIssuer3);
}
} catch (CertificateException ex) {

Logger.getLogger(OCSP.class.getName()).log(Level.SEVERE, null, ex);


}
inStreamIssuer1.close();
inStreamIssuer2.close();
inStreamIssuer3.close();
/*Se genera la petición OCSP con el certificado de la entidad emisora y con el
número de serie del certificado del titular del DNIe*/
OCSPReqGenerator ocspReqGen = new OCSPReqGenerator();
ocspReqGen.addRequest(new CertificateID(CertificateID.HASH_SHA1,
certImportadoIssuer,certUsuario.getSerialNumber()));
OCSPReq ocspReq = ocspReqGen.generate();
URL url = new URL("http://ocsp.dnie.es");
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestProperty("Content-Type", "application/ocsp-request");
con.setRequestProperty("Accept", "application/ocsp-response");
con.setDoOutput(true);
OutputStream out = con.getOutputStream();
DataOutputStream dataOut = new DataOutputStream(new BufferedOutputStream(out));
/*Se escribe la petición*/
dataOut.write(ocspReq.getEncoded());
dataOut.flush();
dataOut.close();
/*Se recoge la respuesta del servidor OCSP*/
InputStream in = (InputStream) con.getContent();
OCSPResp ocspResponse = new OCSPResp(in);
String resp = "";
/*Si la respuesta OCSP es correcta, se verifica el estado del certificado*/
if (ocspResponse.getStatus() == OCSPResponseStatus.SUCCESSFUL) {
CertificateID certID = new CertificateID(CertificateID.HASH_SHA1,
certImportadoIssuer,
certUsuario.getSerialNumber());
BasicOCSPResp basicResp = (BasicOCSPResp) ocspResponse.getResponseObject();
SingleResp[] singleResps = basicResp.getResponses();
for (SingleResp singResp : singleResps) {
CertificateID respCertID = singResp.getCertID();
if (certID.equals(respCertID)) {
Object status = singResp.getCertStatus();
if (status == CertificateStatus.GOOD) {
resp = "Certificado Válido";
} else if (status instanceof org.bouncycastle.ocsp.RevokedStatus) {
resp = "Certificado Revocado";
} else {
resp = "Certificado Desconocido";
}}}
} else {
resp = "Petición no válida";
}
return resp;

You might also like