miércoles, 17 de junio de 2015

TLS/SSL y los problemas con los certificados

Desde hace unos años vengo trabajando con certificados, de SSL/TLS y de firma electrónica para eFactura, ambos funcionan con un esquema similar, solo que uno es para asegurar conexiones y el otro para asegurar la legitimidad de los documentos intercambiados.

Ahora me dispongo a compartir parte de lo que he aprendido, intentando dar una guía rápida que permita entender y solucionar rápidamente los problemas más comunes al trabajar con certificados. Vale la pena dedicarle 5 o 10 minutos para entenderlo porque luego ahorra mucho tiempo y frustraciones.

En mayor o menor medida todos sabemos que cuando vemos el candadito en el navegador, nos indica que es una conexión segura, esto tiene 2 aspectos: la autenticación y la encriptación, ya que no alcanza con encriptar si no sabemos si estamos hablando con quien queremos o un impostor. Siendo la autenticación la primer etapa, es donde surge la mayor parte de los problemas porque requiere tener instalados adecuadamente los certificados.

Esta es una simplificación de como se da la conversación entre un cliente y un servidor:


Los certificados raíz representan Entidades Certificadoras, estas son empresas en las que confiamos que solo emiten certificados a entidades legítimas, por ejemplo confiamos en que no le va a emitir un certificado para example.com a alguien que no sea dueño de ese dominio.

Entonces el servidor responde con su cadena (el certificado raíz no es necesario) y el cliente verifica en su almacén de certificados de confianza si tiene el certificado raíz que completa esa cadena, una vez que lo encuentra usa herramientas criptográficas para asegurarse de que todos los certificados (intermedios y final) son legítimos. La autenticación de cliente es opcional, si el servidor la requiere el cliente le envía su certificado y el servidor hace la validación análoga, pero la mayoría de los servicios web no requieren este tipo de autenticación.

Algunas apreciaciones:
  • El Trust store y el Key store pueden ser el mismo almacén, pero están diferenciados porque tienen funciones distintas. Por ejemplo en Java se configuran por separado y en Windows se manejan todos juntos categorizados según su uso.
  • Un servidor puede actuar como cliente de otro, entonces en el servidor también hay que configurar el Trust store adecuadamente. Esto es muy frecuente en sistemas web que requieren servicios de terceros.
  • En SSL/TLS un servidor debe enviar la cadena con el certificado final y todos los certificados intermedios (puede ser más de uno), el certificado raíz lo puede enviar pero no es necesario porque el cliente igual debe verificar que esté en su Trust store.
  • En firma electrónica es común que los certificados intermedios no se incluyan, por lo que también hay que agregarlos al Trust store. Esto no es lo ideal pero si queremos validar estos documentos no tenemos alternativa.
¿Por qué son necesarios los certificados intermedios?
La razón principal es seguridad. Una entidad certificadora utiliza su clave privada para emitir certificados intermedios, por o que debe ser guardada con altas medidas de seguridad, si se utilizara cada vez que se emite un certificado final significa que tendría un nivel de exposición alto comparado con utilizarla solo cuando se necesita un nuevo certificado intermedio.
Además si se viera comprometido el certificado intermedio, al entidiad certificadora puede revocarlo y emitir un nuevo certificado intermedio, de esta forma, el certificado raíz que ya está instalado en millones de equipos en todo el mundo sigue siendo válido.

Hasta aquí la parte conceptual, ahora algo de información específica de Java.

Troubleshooting en Java

  • java.io.IOException: Keystore was tampered with, or password was incorrect:
    Lo más probable es que tengamos mal cargada la password y por eso no puede leer el Keystore.
  • javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed:
    El error indica que no se pudo construir la cadena desde el certificado final hasta un certificado raíz de confianza. Lo más probable es que no tengamos cargado el certificado raíz o los intermedios en nuestro Trust store. Otra posibilidad es si nos queremos conectar a un servicio con certificado autofirmado, por ejemplo un servidor de mail interno, en ese caso tenemos que importar el certificado autofirmado (final y raíz a la vez).
    Otro escenario común en Uruguay es con los servicios que están certificados por el Correo Urugayo, como los certificados raíz no vienen precargados en Java tenemos que importarlos manualmente.
  • javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificate:
    Este error puede aparecer cuando el servidor nos exige autenticación de cliente y nuestro sistema no le envía un certificado adecuado.

Truststore y Keystore en Java

Se configuran con las siguientes propiedades:
  • javax.net.ssl.trustStore: "/path/to/keystore"
  • javax.net.ssl.trustStoreType: "JKS"
  • javax.net.ssl.trustStorePassword: "changeit"
  • javax.net.ssl.keyStore: "/path/to/keystore"
  • javax.net.ssl.keyStoreType: "PKCS12"
  • javax.net.ssl.keyStorePassword: "contraseña"
y se puede configurar de las siguientes formas:
  • Como parámetro de Java: -Djavax.net.ssl.trustStore=/path/to/keystore
    Recomendado.
  • Con código: System.setProperty("javax.net.ssl.trustStore", "/path/to/keystore");
    No recomendado porque si el Truststore ya fue inicializado esta asignación no va a tener ningún efecto.
En Java el Truststore por defecto se llama "cacerts" y viene cargado con entidades certificadoras donde se encuentran las más comunes. La ubicación varía en cada sistema operativo, en Windows está en la carpeta lib\security\cacerts se la instalación de Java, mientras que en linux varía de una distribución a otra, en general el archivo lib/security/cacerts suele apuntar a una ruta centralizada para cualquier instalación de Java, por ejemplo /etc/pki/java/cacerts.

Además tener en cuenta que los servidores web puede utilizar las ubicaciones por defecto o establecer su propia ubicación, por ejemplo Tomcat usa la por defecto de Java mientras que GlassFish asigna su propia ruta.

Como agregar un certificado raíz o autofirmado al Truststore de Java

Se necesita la herramienta keytool que viene con la JDK (no alcanza con la JRE).

Primero hay que encontrar el archivo cacerts que queremos actualizar.

Para verificar los certificados que hay dentro podemos usar el comando:
> keytool -list -keystore cacerts
la contraseña por defecto es: changeit
Para importar un certificado:
> keytool -import -alias "Nombre del Certicado" -file CertificadoRoot.cer -keystore cacerts
el alias es solo un nombre descriptivo con el que quedará guardado, no es necesario que coincida con nada, solo un nombre con el que nos sea fácil volver a encontrarlo.

Conozco el sitio al que me quiero conectar. ¿Cómo puedo obtener su certificado raíz?

Con un navegador es fácil investigar el certificado, pongo un ejemplo con Chrome, pero en todos se hace de forma similar.

Luego usamos Copy to File para guardarlo y poder importarlo a nuestro almacén.

¿Y si el browser no me muestra la cadena?
Significa que el browser tampoco tiene instalado el certificado raíz, en ese caso vamos a la pestaña Details y le buscamos el Issuer, luego se puede buscar la página oficial del Issuer para descargar sus certificados.


Espero que esta guía les haya sido útil, no entra demasiado en profundidad sino que apunta a explicar conceptualmente como funciona el sistema de certificados y a resolver los problemas más comunes con los que me he encontrado yo y otras personas a las que he ayudado.

viernes, 20 de febrero de 2015

Recuperación de un Windows Server 2003

Hace poco tuvimos un problema, dejó de arrancar el Windows Server 2003 que actuaba de Controlador de Dominio. A veces lograba empezar a iniciar Windows pero antes de terminar de iniciar se apagaba sin ni siquiera una pantalla azul (nunca la extrañe tanto).
Al probar con un Live CD pasaba lo mismo con lo cual se confirmó que existía un problema de hardware, lo cual no era sorprendente ya que tenía unos cuantos años.

El plan era sencillo, comprar un servidor nuevo instalar un Windows Server nuevo y restaurar todo de los backups, pero nunca es tan sencillo, no?

Para poder migrar el Active Directory en un nuevo servidor debe hacerse con ambos servidores online, no se puede recuperar desde un archivo. A su vez como el hardware había fallado la única alternativa era iniciar en un hardware nuevo. El primer paso fue respaldar todo lo que había en los discos en otra PC. Luego utilizamos una PC en desuso para iniciar Windows, pero aparentemente su hardware era demasiado nuevo y no logró arrancar, con lo cual tuvimos que pasar a una PC más vieja y ahí empezamos a tener un poquito más de suerte, pero no se lograba completar el inicio de Windows.

Primer paso de riesgo, utilizando el CD de Windows 2003 hacer una reparación del sistema.
La primera vez tampoco logramos iniciar Windows, así que tuvimos que realizar una reinstalación completa de Windows (sin formatear), aquí empezamos a tener un poco más de suerte y el mismo arrancó pero totalmente limpio.
Algo importante es que este paso elimina la carpeta Windows, así que antes de ejecutarlo es impresindible respaldarla, aunque sea con un LiveCD, de lo contrario sería imposible recuperar la instalación original.
Otra cosa, creo que es importante (aunque no lo pude confirmar) es utilizar la misma contraseña que tenía originalmente o la contraseña de recuperación de Active Directory (DSRM), esta puede ser distinta a la contraseña del Administrador del Dominio.

Una vez que logramos iniciar Windows Server, se instaló el Service Pack 2 y se hizo una restauración del Respaldo. El Respaldo solo tenía el System-State, o sea algunas subcarpetas de Windows, Registro, Active Directory, etc. NOTA: Antes de hacer este paso restaurar manualmente System32 como se muestra más abajo.

Aquí empezaron de vuelta los problemas, al restaurar el estado anterior resultó que al System32 le faltaban montones de DLLs que eran necesarias para un inicio normal, incluso pedía reactivar Windows para poder iniciar sesión, pero fallaba en traer el diálogo de activación y se reiniciaba el sistema.
Después de varios intentos logramos iniciar en modo a prueba de fallos con símbolo del sistema y utilizando el comando explorer trajo el escritorio.
Aquí pudimos recuperar los archivos faltantes de System32 y de toda la carpeta Windows con el siguiente comando:
robocopy Windows\ C:\Windows\ /E /COPYALL /XC
Esto podría hacerse también con un LiveCD, lo importante es copiar solo los archivos faltantes y no reemplazar ningún archivo.

Además aprovechamos para instalar los drivers de la nueva tarjeta de red, que era distinta a la del hardware original.

Después de reiniciar Windwos arrancó normalmente, pidiendo reactivación por cambios de hardware, pero esta vez me daba 3 días para activarlo, así que se pudo iniciar sesión por más que aún no se tenía conectividad de red.

Active Directory levantó y pudimos configurar el nuevo servidor para unirse al dominio, luego se dio de baja el servidor viejo y se dejó el nuevo servidor como principal.

Datos y herramientas que conocí durante el proceso:
  • Para conectar un Windows 2012 a Controlador de Dominio 2003 hay que asegurarse que "el bosque" esté en nivel funcional 2003. Esto requiere primero subir el DC a 2003 y luego el bosque.
    Si hay algún DC viejo desconectado no se permitirá subir el nivel funcional, con lo cual deberá eliminarse manualmente de la base de datos de Active Directory.
  • La base de datos de Active Directory se guarda por defecto en C:\Windows\NTDS\ntds.dit
  • ntdsutil: permite verificar integridad de los archivos de Active Directory, también permite hacer alguna corrección de datos. Por ejemplo fue necesaria para eliminar de la base de Active Directory metadatos obsoletos de un servidor viejo que ya no existía pero pretendía seguir replicando contra él.
  • esentutl: permite reparar un ntds.dit dañado, luego de reparar hay que quitar los .log de la carpeta de NTDS y reiniciar.
  • dsamain: permite levantar el ntds.dit como un LDAP, y se puede consultar con la herramienta ldp.exe, esto puede ser muy útil se se quiere consultar la información para crear un dominio desde cero.
  • ProfWiz: Afortunadamente no lo tuve que usar, pero me lo recomendaron para migrar perfiles de Windows de un dominio viejo a uno nuevo (en el caso de crearlo desde cero).
La lección principal aprendida es que conviene siempre tener más de un Controlador de Dominio, tal vez lo más sencillo sea tener una máquina virtual que funcione como controlador principal o de respaldo, esto es bueno ya que una máquina virtual debería ser bastante más fácil de restaurar.