Crear un certificado SSL wildcard autofirmado con OpenSSL

Alguna vez nos ha tocado crear certificados autofirmados y es una tarea un poco odiosa, pues con esta entrada voy a explicar como crear un certificado autofirmado comodín o wildcard para poder utilizar en cada web del mismo dominio.

Creamos la clave privada del certificado intermedio.

 openssl genrsa -des3 -out CAPrivate.key 2048


Generamos el certificado intermedio.

 openssl req -x509 -new -nodes -key CAPrivate.key -sha256 -days 365 -out CAPrivate.pem

Creamos clave privada.

 openssl genrsa -out MyPrivate.key 2048

Generamos el CSR

 openssl req -new -key MyPrivate.key -extensions v3_ca -out MyRequest.csr

Creamos el fichero openssl.ss.cnf para crear la entrada de dominio wildcard a utilizar.

basicConstraints=CA:FALSE
subjectAltName=DNS:*.mydomain.tld
extendedKeyUsage=serverAuth

Creamos el certificado utilizando el CSR creado.

 openssl x509 -req -in MyRequest.csr -CA CAPrivate.pem -CAkey CAPrivate.key -CAcreateserial -extfile openssl.ss.cnf -out MyCert.crt -days 365 -sha256

Y ya tendríamos el certificado creado, teniendo los siguientes ficheros:

Clave privada: MyPrivate.key
Certificado intermedio: CAPrivate.pem
Certificado wildcard: MyCert.crt

Si quisiéramos utilizar el navegador en un servidor web tipo nginx pues solo tendríamos que crear un fichero bundle fusionando el certificado intermedio y el wildcard.

cat MyCert.crt CAPrivate.pem > MyCert.bundle.crt 

Como convertir certificado Let’s encrypt en keystore java para tomcat (jks)

Todos conocemos Let’s encrypt, en un servicio muy comido que nos permite instalar certificados SSL seguros de manera cómoda y gratuita.

Pero desgraciadamente no los crea en formato jks y no podemos utilizarlos en servidores de aplicaciones tomcat.

Pero esto lo podemos solucionar de una manera muy fácil utilizando las herramientas openssl y keytool que nos permiten convertirlo en formato jks.

Lo primero que haremos es con openssl exportar la clave privada (privkey1.pem) y el certificado (fullchain1.pem) y guardarlo en un fichero p12 (fichero.p12) con el siguiente comando:

openssl pkcs12 -export -out fichero.p12 -inkey privkey1.pem -in fullchain1.pem -name "tomcat-cert"

A continuación con keytool generaremos el llavero jks (llavero.jks) con el siguiente comando:

keytool -importkeystore -srckeystore fichero.p12 -srcstoretype pkcs12 -destkeystore llavero.jks

Y ya tendríamos el certificado keystore creado.

Lo ultimo que tendríamos que haces es configurar el server.xml de tomcat para que utiliza el llavero creado, añadiendo la password que usamos para su creación (en el ejemplo “secreta”).

<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150" SSLEnabled="true" scheme="https" secure="true" URIEncoding="UTF-8"
        keystoreFile="llavero.jks"
keystorePass="secreta" keyAlias="tomcat-cert"
clientAuth="false" sslProtocol="TLS" />

Poner certificado https en nginx con Let’s encrypt y Docker

Poner certificados https muchas veces nos da verdaderos dolores de cabeza, pero para solucionarnos este problema se crearon los certificados Let’s encrypt que de una manera sencilla nos permite utilizar certificados gratuitos y renovarlos periódicamente.

En esta entrada voy a explicar a poner el certificado en entornos con docker y lo primero que vamos a hacer es crear el docker-compose.yml donde crearemos el contenedor para el nginx.

version: '3'

services:
  nginx:
    image: nginx:latest
    ports:
      - 80:80
      - 443:443
    restart: always
    volumes:
      - ./nginx/conf.d/:/etc/nginx/conf.d/:ro

A continuación creamos el fichero de configuración del nginx ( ./nginx/conf.d/default.conf ) cambiando example.org pro nuestro dominio.

server {
    listen 80;
    listen [::]:80;

    server_name example.org www.example.org;
    server_tokens off;

    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

    location / {
        return 301 https://example.org$request_uri;
    }
}

Ahora arrancamos el contenedor y vemos como el nginx es accesible.

docker-compose up -d

El siguiente paso es crear el servicio certbot que se encargara de crear nuestro certificado editando el fichero docker-compose.yml.

version: '3'

services:

  webserver:
    image: nginx:latest
    ports:
      - 80:80
      - 443:443
    restart: always
    volumes:
      - ./nginx/conf.d/:/etc/nginx/conf.d/:ro
      - ./certbot/www/:/var/www/certbot/:ro
      - ./certbot/conf.d/:/etc/nginx/ssl/:ro

  certbot:
    image: certbot/certbot:latest
    volumes:
      - ./certbot/www/:/var/www/certbot/:rw
      - ./certbot/conf.d/:/etc/letsencrypt/:rw

Volvemos a lanzar el docker-compose para crear los directorios que utilizara certbot

docker-compose up -d

Una vez cambiado el docker-compose.yml lanzamos el comando para crear los certificados, cambiando el dominio example.org por el nuestro.

docker-compose run --rm  certbot certonly --webroot --webroot-path /var/www/certbot/ -d example.org

Una vez que ya tengamos los certificados creados editamos el fichero de configuración del nginx (./nginx/conf.d/default.conf) cambiando el dominio example.org por el nuestro.

En el ejemplo uso el nginx como proxy para servir un tomcat.

server {
    listen 80;
    listen [::]:80;

    server_name example.org www.example.org;
    server_tokens off;

    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

    location / {
        return 301 https://example.org$request_uri;
    }
}

server {
    listen 443 default_server ssl http2;
    listen [::]:443 ssl http2;

    server_name example.org;

    ssl_certificate /etc/nginx/ssl/live/example.org/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/live/example.org/privkey.pem;
    
    location / {
      proxy_pass      http://127.0.0.1:8080;
    }
}

Ya por ultimo paramos el contenedor del nginx y recreamos los contenedores.

docker stop nginx

docker-compose up -d

Y ya tendriamos nuestra web accesible con https y certificado seguro.

Como ultimo paso añado el comando que tenemos que utilizar cuando queramos renovar el certificado.

docker-compose run --rm certbot renew

Instalar certificado gratuito ssl con Let’s Encrypt en tomcat

Es comun utilizar Let’s Encrypt par poner certificados gratuitos seguros en nuestros dominios, ponerlos en apache o nginx es una tarea sencilla, pero todos hemos sufrido la tarea de poner un certificado seguro en un llavero (Java KeyStore) de tomcat.

Con esta pequeña entrada voy a explicar paso a paso como poner un certificado gratuito Let’s Encrypt en tomcat.

Para realizar los pasos necesitaremos tener instalado en el sistema keytool (viene con el jdk) y certboot (https://certbot.eff.org/).

Creamos un llavero JKS (letsencrypt.jks) con una clave RSA 2048, con la entrada de dominio (midominio.es)

keytool -genkeypair -alias simple-cert -keyalg RSA -keysize 2048 -keystore letsencrypt.jks -dname "CN=midominio.es" -storepass password12345

Agregamos una segunda clave RSA 4096 – (san-cert)

keytool -genkeypair -alias san-cert -keyalg RSA -keysize 4096 -keystore letsencrypt.jks -dname "CN=midominio.es" -storepass password12345

Creamos un CSR para simple-cert y un CSR para san-cert

keytool -certreq -alias simple-cert -keystore letsencrypt.jks -file midominio.csr -storepass password12345 -ext san=dns:midominio.es

Creamos el full certificate chain con certboot (certificado Let’s Encrypt).

certbot certonly --manual --csr midominio.csr --preferred-challenges "dns"

Nos creara una serie de certificados y debemos de quedarnos con el full certificate chain.

Successfully received certificate.

Certificate is saved at:            C:\Program Files (x86)\Certbot\bin\0000_cert.pem
Intermediate CA chain is saved at:  C:\Program Files (x86)\Certbot\bin\0000_chain.pem
Full certificate chain is saved at: C:\Program Files (x86)\Certbot\bin\0001_chain.pem
This certificate expires on 2023-03-07.

Añadimos el certificado al keystore (clic YES cuando pregunte).

keytool -importcert -alias simple-cert -keystore letsencrypt.jks -storepass password12345 -file 0001_chain.pem

Y ya tendriamos el certifiado creado y solo necesitariamos añadirlo en el fichero de configuración del tomcat (server.xml).

<Connector port="443" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150" SSLEnabled="true" scheme="https" secure="true" URIEncoding="UTF-8"
keystoreFile="conf\ssl\letsencrypt.jks"
keystorePass="password12345" keyAlias="simple-cert"
clientAuth="false" sslProtocol="TLS" />

—- RENOVAR CERTIFICADO —-

Los certificados Let’s Encrypt , caducan a los tres meses, con lo que es posible que al intentar reniovarlo nos de problemas, lo unico que tendremos es que realizar los mismos pasos y cuando lancemoz el comando certbot, crear la entrada dns que nos pidan por consola.

Please deploy a DNS TXT record under the name:

_acme-challenge.midominio.es.

with the following value:

t8TpRgmScIuzwwrXgsCEhqt1VaV4s7EkxEziWoOCJ2h

Como solucionar el error: unable to negotiate wit port 22: no matching key exchange method found

Ya estamos con los errores atipicos, si te ha parecido alguna vez el error unable to negotiate wit port 22: no matching key exchange method found, voy a explicarte de manera sencilla como solucionarlo.

Esto es debido a que el origen y destino tienen diferentes librerias ssl y no puden realizar correctamente la negociación para la conexión ssh, saltano un error de este tipo.

[root@pruebas~]# ssh pruebas@192.168.1.2
unable to negotiate wit port 22: no matching key exchange method found. Their offer : diffie-hellman-group-exchange-sha1,diffie-hellman-group14-exchange-sha1, diffie-hellman-group1-exchange-sha1

La solucion es bastante sencilla y solo ahce falta añadir el cifrado del algoritmo a utilizar, como muestro en el ejemplo a continuación.

[root@pruebas~]# ssh -oKexAlgorithms=+diffie-hellman-group1-sha1 pruebas@192.168.1.2

Vulnerabilidades SSL/TLS en Apache – corregir ataques POODLE / BEAST / SWEET32 y deshabilitar SSL

Escribo esta entrada para tener actualizado al día el apache de posibles ataques.

Comprobando con nmap el puerto 443, se puede ver como muchos apaches utilizan cifrados inseguros (incluso en sistemas robustos como centos 7).

Ejemplo:

nmap -p 443 --script ssl-enum-ciphers 192.168.1.2
Starting Nmap 7.80 ( https://nmap.org ) at 2020-05-27 08:59 Hora de ver. Europa Occidental
Nmap scan report for 192.168.1.2
Host is up (0.18s latency).

PORT    STATE SERVICE
443/tcp open  https
| ssl-enum-ciphers: 
|   TLSv1.0: 
|     ciphers: 
|       TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA (dh 2048) - C
|       TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA (secp256r1) - C
|       TLS_ECDHE_RSA_WITH_RC4_128_SHA (secp256r1) - C
|       TLS_RSA_WITH_3DES_EDE_CBC_SHA (rsa 2048) - C
|       TLS_RSA_WITH_RC4_128_MD5 (rsa 2048) - C
|       TLS_RSA_WITH_RC4_128_SHA (rsa 2048) - C
|     compressors: 
|       NULL
|     cipher preference: client
|     warnings: 
|       64-bit block cipher 3DES vulnerable to SWEET32 attack
|       64-bit block cipher IDEA vulnerable to SWEET32 attack
|       Broken cipher RC4 is deprecated by RFC 7465
|       Ciphersuite uses MD5 for message integrity

Como podemos ver, son unos cuantos los cifrados inseguros.

Para corregirlo lo que haremos es añadir estas dos directivas en el fichero de configuración del apache. (excluir cifrado ssl y cifrados vulnerables)

SSLProtocol ALL -SSLv2 -SSLv3
SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL:!3DES:!MD5:!IDEA:!RC4:!DES:!DES40:!aNULL

Reiniciando el apache ya lo tendremos protegido de vulnerabilidades.