Lo hice y lo entendí

El blog de Vicente Navarro
22 feb

Crear los certificados SSL para nuestro servidor web HTTPS con Apache, OpenSSL y Debian Lenny

Cuando escribimos nuestra contraseña para entrar al panel de administración de WordPress, ésta va en texto plano. En una red WiFi, por ejemplo, cualquiera podría ver muy fácilmente nuestra contraseña sólo con capturar la paquetes de la red mientras nos estamos registrando.

Aunque hay soluciones parciales (Semisecure Login Reimagined), la solución definitiva, como siempre, pasa por usar HTTPS o, lo que es lo mismo, HTTP sobre SSL. Desde la versión 2.6, WordPress permite usar SSL fácilmente para el panel de administrador. Así que me puse a hacer pruebas para configurar SSL en mi servidor web.

Sin embargo, ocurre una cosa muy interesante con el protocolo SSL cuando se usa con HTTP: que no se pueden servir fácilmente múltiples sitios virtuales encriptados con SSL desde una misma IP.

En el contexto de los servidores web, hablamos de sitios virtuales (Apache Virtual Host documentation) cuando servimos páginas de diferentes dominios desde un único servidor, en muchos casos compartiendo la IP y en otros, cada dominio con una IP diferente, posiblemente con interfaces virtuales. Cuando usamos HTTP sin SSL, el servidor sabe qué página en concreto estamos solicitando porque el cliente HTTP (el navegador) lo indica en la cabecera Host:

GET /blog/ HTTP/1.1
Host: www.vicente-navarro.com
User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; es-ES; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.10 (intrepid) Firefox/3.0.6
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: es,en-us;q=0.7,en;q=0.3
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive

Sin embargo, cuando se usa SSL, la negociación entre los extremos y la encriptación ocurre en una capa inferior, antes de que éstos comiencen a usar el protocolo HTTP. Por ello, no es trivial configurar diferentes certificados para diferentes sitios web virtuales. En la configuración típica, sólo podremos usar un certificado compartido para todas las páginas que se sirvan por HTTPS desde un único servidor web, a menos que usemos una IP diferente para cada sitio: Apache SSL/TLS Strong Encryption: FAQ: Why can’t I use SSL with name-based/non-IP-based virtual hosts?, Apache SSL/TLS Strong Encryption: FAQ: Why is it not possible to use Name-Based Virtual Hosting to identify different SSL virtual hosts?.

Para este inconveniente hay workarounds (TLS Support for name-based virtual servers) y soluciones definitivas con el Server Name Indication (SNI). Apache 2.2 no soporta SNI, pero el módulo de Apache mod_gnutls (incluido en Debian Lenny: libapache2-mod-gnutls) nos permitiría usarlo. Desafortunadamente, aunque Firefox (>=2), Safari, Chrome y Opera soportan esta extensión del protocolo, Internet Explorer 6 e Internet Explorer 7 para Windows XP no soportan SNI, por lo que no podemos usarla de momento por motivos obvios.

Por todos estos motivos, descubrí que con los hostings profesionales no resulta fácil o, mejor dicho, barato, tener un servidor SSL. Es lo que me va a impedir a mí poder configurar SSL para el panel de administración de LHYLE.

Sin embargo, podemos seguir estudiando cómo podríamos hacerlo si lo que tenemos es un Hosting Casero o si le hemos contratado un servidor dedicado a nuestro proveedor de hosting.

Habilitar el servidor HTTPS en Debian Lenny

Si instalamos los paquetes de Apache 2.2 en un sistema con la recién liberada Debian Lenny, ya tendremos por defecto configurado un servidor HTTPS junto con el típico HTTP. En Debian Etch no era así, sino que sólo se configuraba el servidor HTTP. Así, si en Debian Etch el fichero /etc/apache2/sites-available/default era así:

NameVirtualHost *
<VirtualHost *>
        ServerAdmin webmaster@localhost

        DocumentRoot /var/www/

...
		
</VirtualHost>

Ahora, en Debian Lenny, tenemos un fichero /etc/apache2/ports.conf (que es incluido desde el /etc/apache2/apache2.conf) con este contenido:

NameVirtualHost *:80
Listen 80

<IfModule mod_ssl.c>
    # SSL name based virtual hosts are not yet supported, therefore no
    # NameVirtualHost statement here
    Listen 443
</IfModule>

y ahora, el /etc/apache2/sites-available/default menciona específicamente el puerto 80 en la directiva VirtualHost, para diferenciar las peticiones al puerto 80 (HTTP) de las peticiones al puerto 443 (HTTPS):

<VirtualHost *:80>
        ServerAdmin webmaster@localhost

        DocumentRoot /var/www/

...
		
</VirtualHost>

de modo que ahora hay una nueva configuración de sitio disponible, la /etc/apache2/sites-available/default-ssl:

<IfModule mod_ssl.c>
<VirtualHost _default_:443>
        ServerAdmin webmaster@localhost

        DocumentRoot /var/www/

...

        #   SSL Engine Switch:
        #   Enable/Disable SSL for this virtual host.
        SSLEngine on

        #   A self-signed (snakeoil) certificate can be created by installing
        #   the ssl-cert package. See
        #   /usr/share/doc/apache2.2-common/README.Debian.gz for more info.
        #   If both key and certificate are stored in the same file, only the
        #   SSLCertificateFile directive is needed.
        SSLCertificateFile    /etc/ssl/certs/ssl-cert-snakeoil.pem
        SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key
		
	BrowserMatch ".*MSIE.*" \
                nokeepalive ssl-unclean-shutdown \
                downgrade-1.0 force-response-1.0

</VirtualHost>
</IfModule>

Como hemos comentado antes, mientras que podemos añadir a la configuración de Apache tantos ficheros de sitios virtuales para HTTP que comiencen por <VirtualHost *:80> como queramos, para HTTPS, en el puerto 443, sólo podremos tener uno (a menos que configuremos diferentes IPs para los diferentes sitios).

Las líneas claves para activar el SSL son éstas:

SSLEngine on
SSLCertificateFile    /etc/ssl/certs/ssl-cert-snakeoil.pem
SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key

Dichos certificados “de aceite de serpiente” (Wikipedia: Snake oil (cryptography)) los genera el script de postinstalación del paquete ssl-cert de Debian asociados al hostname del sistema.

Aunque recién instalado, el Apache 2.2 de Debian Lenny está preparado para servir contenido HTTPS, aún hay que habilitar el sitio y el módulo de SSL. Para ello usaremos a2ensite y a2enmod:

# a2enmod ssl
Enabling module ssl.
See /usr/share/doc/apache2.2-common/README.Debian.gz on how to configure SSL and create self-signed certificates.
Run '/etc/init.d/apache2 restart' to activate new configuration!

# a2ensite default-ssl
Enabling site default-ssl.
Run '/etc/init.d/apache2 reload' to activate new configuration!

# /etc/init.d/apache2 restart

Ahora ya podríamos conectarnos por HTTPS: https://subdominio.dominio.tld. Sin embargo, al estar usando el certificado “de aceite de serpiente”, lo que nos encontraremos será con que el navegador nos da una o dos advertencias sobre el dominio. Una segura porque el certificado no está firmado por una autoridad de confianza y tal vez otra porque el dominio, hostname o IP que estamos usando para acceder al sitio no coincida con el que indica el certificado.

Por ejemplo, yo he instalado Debian Lenny en un sistema cuyo nombre es telemaco, pero quiero acceder al sitio web seguro https://desarrollo.vicente-navarro.com que he configurado en telemaco. Me encontraría con los errores comentados, uno porque el certificado es para acceder al sitio web https://telemaco, y otro porque el certificado no está firmado por una autoridad reconocida:

Firefox: Secure Connection Failed

Si decidimos seguir adelante y examinamos el certificado, veremos que realmente es un certificado para el sitio telemaco, no para desarrollo.vicente-navarro.com:

Firefox: Certificate Viewer: telemaco

Por tanto, si accedemos con https://telemaco, ya sólo encontraremos el error de que el certificado no es de fiar, pero no el de que el certificado no es para este sitio:

Firefox: Secure Connection Failed 2

Necesitamos resolver estos problemas con el certificado que estamos usando.

Crear un certificado autofirmado

Veamos primero cómo conseguir un certificado autofirmado asociado a nuestro sitio. Para ello, podemos usar el siguiente comando (Apache SSL/TLS Strong Encryption FAQ: How do I create a self-signed SSL Certificate for testing purposes?):

#  openssl req -new -x509 -nodes -out /etc/ssl/certs/desarrollo.vicente-navarro.com_self.crt -keyout /etc/ssl/private/desarrollo.vicente-navarro.com_self.key
Generating a 1024 bit RSA private key
......++++++
....................................................................++++++
writing new private key to '/etc/ssl/private/desarrollo.vicente-navarro.com_self.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:ES
State or Province Name (full name) [Some-State]:Spain
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Desarrollo de Lo hice y lo entendi
Organizational Unit Name (eg, section) []:El blog de Vicente Navarro
Common Name (eg, YOUR name) []:desarrollo.vicente-navarro.com
Email Address []:correodesarrollo@vicente-navarro.com

Y ahora, apuntando a dicho certificado en la configuración del sitio:

SSLCertificateFile    /etc/ssl/certs/desarrollo.vicente-navarro.com_self.crt
SSLCertificateKeyFile /etc/ssl/private/desarrollo.vicente-navarro.com_self.key

y tras reiniciar el servidor, al conectarnos al sitio, el navegador nos advertirá de que el certificado no es de fiar pero al menos, sí que corresponde a la página en cuestión. Como es nuestro propio sitio web y, por tanto, seguro que nos vamos a fiar de él, podríamos añadir una excepción que se almacene de forma permanente en nuestro navegador para, finalmente, usar encriptación sin problemas. En el caso que he expuesto al principio, el mío de querer usar SSL en el interfaz de administración de WordPress, tener un certificado así es más que suficiente, ya que nadie más aparte de mí debería de necesitar confiar en el certificado.

Firefox: Add Security Exception

Firefox: Certificate Viewer: desarrollo.vicente-navarro.com self-signed

La excepción se almacena en forma de certificado en la pestaña de autoridades reconocidas y en forma de entrada en la pestaña de servidores:

Firefox: Certificate Manager

Firefox: Certificate Manager 2

Es necesario tener el servidor explícitamente autorizado en la pestaña de servidores porque si editamos las propiedades del certificado en el navegador, veremos que, por defecto, no sirve para identificar sitios web. Si lo modificáramos, no sería necesaria la excepción de la pestaña de servidores:

Firefox: Certificate Settings

Crear un certificado firmado por nuestra propia autoridad certificadora

Si lo que tenemos entre manos es un proyecto muy serio, y necesitamos crear un certificado SSL firmado de verdad por alguna de las autoridades certificadoras cuyos certificados raíz están ya incluidos en todos los navegadores estándar (p.e. VeriSign), tras hacer la compra y seguir todos los trámites necesarios, tendremos que crear una clave privada y generar una petición de certificado para firmar y enviársela a la autoridad certificadora: Apache SSL/TLS Strong Encryption: FAQ: How do I create a real SSL Certificate?.

Sin embargo, si estamos en el entorno de la Intranet de una compañía, donde podríamos controlar que todos los sistemas incluyeran el certificado raíz de la misma, o, simplemente, para estudiar cómo hacerlo, podríamos generarnos nuestro propio certificado raíz, autoproclamándonos a nosotros mismos como autoridad certificadora.

Veamos cómo hacerlo con el script el script CA.pl de OpenSSL, que en Debian está bajo /usr/lib/ssl/misc/.

Creamos un nuevo certificado raíz para la autoridad certificadora “Super Coco Certification Authority”, de la empresa “Super Coco Inc.”:

# ./CA.pl -newca
CA certificate filename (or enter to create)

Making CA certificate ...
Generating a 1024 bit RSA private key
.......................................................................................++++++
......................++++++
writing new private key to './demoCA/private/cakey.pem'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:ES
State or Province Name (full name) [Some-State]:Spain
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Super Coco Inc.
Organizational Unit Name (eg, section) []:Barrio Sesamo
Common Name (eg, YOUR name) []:Super Coco Certification Authority
Email Address []:supercoco@barriosesamo.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
Using configuration from /usr/lib/ssl/openssl.cnf
Enter pass phrase for ./demoCA/private/cakey.pem:
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number:
            bf:8a:98:f2:48:c0:84:68
        Validity
            Not Before: Feb 18 19:02:57 2009 GMT
            Not After : Feb 18 19:02:57 2012 GMT
        Subject:
            countryName               = ES
            stateOrProvinceName       = Spain
            organizationName          = Super Coco Inc.
            organizationalUnitName    = Barrio Sesamo
            commonName                = Super Coco Certification Authority
            emailAddress              = supercoco@barriosesamo.com
        X509v3 extensions:
            X509v3 Subject Key Identifier: 
                BD:85:EB:33:B0:0B:06:74:9A:F3:AB:18:95:D5:4B:CB:76:B8:EA:83
            X509v3 Authority Key Identifier: 
                keyid:BD:85:EB:33:B0:0B:06:74:9A:F3:AB:18:95:D5:4B:CB:76:B8:EA:83
                DirName:/C=ES/ST=Spain/O=Super Coco Inc./OU=Barrio Sesamo/CN=Super Coco Certification Authority/emailAddress=supercoco@barriosesamo.com
                serial:BF:8A:98:F2:48:C0:84:68

            X509v3 Basic Constraints: 
                CA:TRUE
Certificate is to be certified until Feb 18 19:02:57 2012 GMT (1095 days)

Write out database with 1 new entries
Data Base Updated

Vale, ya somos autoridad certificadora. Ahora vamos a generar una clave privada y una petición de certificado para el sitio web desarrollo.vicente-navarro.com:

# ./CA.pl -newreq
Generating a 1024 bit RSA private key
.................++++++
.........................++++++
writing new private key to 'newkey.pem'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:ES
State or Province Name (full name) [Some-State]:Spain
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Desarrollo de Lo hice y lo entendi
Organizational Unit Name (eg, section) []:El blog de Vicente Navarro
Common Name (eg, YOUR name) []:desarrollo.vicente-navarro.com
Email Address []:correodesarrollo@vicente-navarro.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
Request is in newreq.pem, private key is in newkey.pem

Ahora, con la clave privada del certificado raíz, firmamos la petición de certificado, para que éste ya esté completo:

# ./CA.pl -sign
Using configuration from /usr/lib/ssl/openssl.cnf
Enter pass phrase for ./demoCA/private/cakey.pem:
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number:
            bf:8a:98:f2:48:c0:84:69
        Validity
            Not Before: Feb 18 19:06:09 2009 GMT
            Not After : Feb 18 19:06:09 2010 GMT
        Subject:
            countryName               = ES
            stateOrProvinceName       = Spain
            organizationName          = Desarrollo de Lo hice y lo entendi
            organizationalUnitName    = El blog de Vicente Navarro
            commonName                = desarrollo.vicente-navarro.com
            emailAddress              = correodesarrollo@vicente-navarro.com
        X509v3 extensions:
            X509v3 Basic Constraints: 
                CA:FALSE
            Netscape Comment: 
                OpenSSL Generated Certificate
            X509v3 Subject Key Identifier: 
                20:7C:02:85:3D:52:2B:88:57:1E:A9:1B:F1:92:CF:70:74:78:00:48
            X509v3 Authority Key Identifier: 
                keyid:BD:85:EB:33:B0:0B:06:74:9A:F3:AB:18:95:D5:4B:CB:76:B8:EA:83

Certificate is to be certified until Feb 18 19:06:09 2010 GMT (365 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
Signed certificate is in newcert.pem

Los nuevos ficheros y directorios que encontraremos en este directorio tras estos tres comandos (“CA.pl -newca“, “CA.pl -newreq” y “CA.pl -sign“) son:

# ll
total 52
drwxr-xr-x 3 root root 4096 2009-02-18 20:06 ./
drwxr-xr-x 4 root root 4096 2009-01-13 18:25 ../
-rwxr-xr-x 1 root root 5875 2009-01-07 19:04 CA.pl*
-rwxr-xr-x 1 root root 3784 2009-01-07 19:04 CA.sh*
-rwxr-xr-x 1 root root  119 2009-01-07 19:04 c_hash*
-rwxr-xr-x 1 root root  152 2009-01-07 19:04 c_info*
-rwxr-xr-x 1 root root  112 2009-01-07 19:04 c_issuer*
-rwxr-xr-x 1 root root  110 2009-01-07 19:04 c_name*
drwxr-xr-x 6 root root 4096 2009-02-18 20:06 demoCA/ ← Directorio que contiene el certificado raíz y su clave privada (demoCA/cacert.pem es el certificado y demoCA/private/cakey.pem es la clave privada)
-rw-r--r-- 1 root root 3532 2009-02-18 20:06 newcert.pem ← Certificado de desarrollo.vicente-navarro.com firmado por la autoridad certificadora
-rw-r--r-- 1 root root  963 2009-02-18 20:05 newkey.pem ← Clave privada del certificado
-rw-r--r-- 1 root root  781 2009-02-18 20:05 newreq.pem ← Petición de certificado para firmar

Ahora podemos mover el certificado y su clave a /etc/ssl/:

# mv newkey.pem /etc/ssl/private/desarrollo.vicente-navarro.com.key 
# mv newcert.pem /etc/ssl/certs/desarrollo.vicente-navarro.com.crt

y cambiar la configuración del sitio para que lo use:

SSLCertificateFile    /etc/ssl/certs/desarrollo.vicente-navarro.com.crt
SSLCertificateKeyFile /etc/ssl/private/desarrollo.vicente-navarro.com.key

tras lo que tendremos que reiniciar el servidor web.

El fichero demoCA/cacert.pem es el certificado raíz de la nueva autoridad certificadora. Es un certificado X.509 con formato PEM. Ese fichero tenemos que copiarlo a los sistemas que vayan a acceder a nuestro sistema e importar el certificado en sus navegadores. Es muy importante que a la hora de importar el certificado, le indiquemos al navegador que el certificado sirve para identificar servidores web:

Firefox: Certificate Import

Firefox: Certificate Manager Super Coco Certificate Authority

Finalmente, éste es el certificado que el sitio https://desarrollo.vicente-navarro.com presentará, firmado por la autoridad certificadora “Super Coco Certification Authority”, y que nuestro navegador reconocerá, puesto que anteriormente le hemos importado el certificado y le hemos dicho que sirve para identificar sitios web:

Firefox: Certificate Viewer: desarrollo.vicente-navarro.com

En Windows, si al fichero del certificado le cambiamos la extensión a .cer, Windows reconocerá el tipo de archivo y podremos hacer doble click sobre él para importar el certificado en Internet Explorer:

cacert.cer

Internet Explorer: Install Certificate

Internet Explorer: Install Certificate 2

Cuidado con ponerle contraseña a la clave privada

Ahora me gustaría hacer un comentario sobre la contraseña que nos pide OpenSSL para ponerle a la clave privada del certificado (no a la del certificado raíz). En los ejemplos anteriores nos la ha pedido y le hemos puesto una. En principio, podría ser buena idea ponérsela, pero tenemos que tener en cuenta que si lo hacemos, tendremos que introducirla cada vez que reiniciemos el servidor, incluso en el arranque de la máquina, algo que puede ser muy inconveniente:

# apache2ctl stop
# apache2ctl start
Apache/2.2.9 mod_ssl/2.2.9 (Pass Phrase Dialog)
Some of your private key files are encrypted for security reasons.
In order to read them you have to provide the pass phrases.

Server desarrollo.vicente-navarro.com:443 (RSA)
Enter pass phrase:

OK: Pass Phrase Dialog successful.

De hecho, esto podría confundirnos en ocasiones porque el comando “apache2ctl restart” simplemente no nos pide la contraseña y no vuelve a arrancar el servidor. La solución pasa por generar el certificado (o la petición del mismo) sin protección con contraseña con el comando “CA.pl -newreq-nodes“). Fijémonos en que esto mismo ya lo habíamos hecho cuando generamos el certificado autofirmado (openssl req -new -x509 -nodes):

# ./CA.pl -newreq-nodes
Generating a 1024 bit RSA private key
.............++++++
..................................++++++
writing new private key to 'newkey.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:ES
State or Province Name (full name) [Some-State]:Spain
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Desarrollo de Lo hice y lo entendi
Organizational Unit Name (eg, section) []:El blog de Vicente Navarro
Common Name (eg, YOUR name) []:desarrollo.vicente-navarro.com
Email Address []:correodesarrollo@vicente-navarro.com
 
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
Request is in newreq.pem, private key is in newkey.pem

Operaciones con el comando openssl

Podemos examinar los certificados con el comando “openssl x509“:

# openssl x509 -noout -text -in /etc/ssl/certs/desarrollo.vicente-navarro.com.crt 
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            bf:8a:98:f2:48:c0:84:69
        Signature Algorithm: sha1WithRSAEncryption
        Issuer: C=ES, ST=Spain, O=Super Coco Inc., OU=Barrio Sesamo, CN=Super Coco Certification Authority/emailAddress=supercoco@barriosesamo.com
        Validity
            Not Before: Feb 18 19:06:09 2009 GMT
            Not After : Feb 18 19:06:09 2010 GMT
        Subject: C=ES, ST=Spain, O=Desarrollo de Lo hice y lo entendi, OU=El blog de Vicente Navarro, CN=desarrollo.vicente-navarro.com/emailAddress=correodesarrollo@vicente-navarro.com
...

y podemos ver la clave con el comando “openssl rsa“:

# openssl rsa -noout -text -in /etc/ssl/private/desarrollo.vicente-navarro.com.key

También podemos usar “openssl verify” para chequear el certificado contra el certificado raíz, pero si no hemos copiado el certificado raíz a /etc/ssl/certs/, el comando fallará:

# openssl verify desarrollo.vicente-navarro.com.crt 
desarrollo.vicente-navarro.com.crt: /C=ES/ST=Spain/O=Desarrollo de Lo hice y lo entendi/OU=El blog de Vicente Navarro/CN=desarrollo.vicente-navarro.com/emailAddress=mail@example.com
error 20 at 0 depth lookup:unable to get local issuer certificate

De hecho, no es suficiente sólo con copiar el certificado:

# cp -p /usr/lib/ssl/misc/demoCA/cacert.pem /etc/ssl/certs/supercocoauthority.pem

sino que también es necesario obtener su hash:

# cd /etc/ssl/certs/
# openssl x509 -in supercocoauthority.pem -noout -hash
628f4309

y crear un enlace al certificado cuyo nombre sea el hash con extensión .0:

# ln -s supercocoauthority.pem 628f4309.0

para que el certificado raíz sea encontrado automáticamente por la harramienta openssl:

# openssl verify desarrollo.vicente-navarro.com.crt
desarrollo.vicente-navarro.com.crt: OK

Con el comando “openssl s_client” podemos probar que la conexión funciona. Sin embargo, curiosamente, a diferencia de cómo funciona “openssl verify“, el “openssl s_client” no encuentra los certificados si no le especificamos el directorio donde buscarlos explícitamente con la opción -CApath:

# openssl s_client -connect desarrollo.vicente-navarro.com:443
CONNECTED(00000003)
depth=0 /C=ES/ST=Spain/O=Desarrollo de Lo hice y lo entendi/OU=El blog de Vicente Navarro/CN=desarrollo.vicente-navarro.com/emailAddress=correodesarroll@vicente-navarro.com
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 /C=ES/ST=Spain/O=Desarrollo de Lo hice y lo entendi/OU=El blog de Vicente Navarro/CN=desarrollo.vicente-navarro.com/emailAddress=correodesarroll@vicente-navarro.com
verify error:num=27:certificate not trusted
verify return:1
depth=0 /C=ES/ST=Spain/O=Desarrollo de Lo hice y lo entendi/OU=El blog de Vicente Navarro/CN=desarrollo.vicente-navarro.com/emailAddress=correodesarrollo@vicente-navarro.com
verify error:num=21:unable to verify the first certificate
verify return:1
...
# openssl s_client -CApath /etc/ssl/certs/ -connect desarrollo.vicente-navarro.com:443
CONNECTED(00000003)
depth=1 /C=ES/ST=Spain/O=Super Coco Inc./OU=Barrio Sesamo/CN=Super Coco Certification Authority/emailAddress=supercoco@barriosesamo.com
verify return:1
depth=0 /C=ES/ST=Spain/O=Desarrollo de Lo hice y lo entendi/OU=El blog de Vicente Navarro/CN=desarrollo.vicente-navarro.com/emailAddress=correodesarrollo@vicente-navarro.com
verify return:1
...

Probar la conexión con wget

También podemos probar la conexión en línea de comandos con wget. Si hemos copiado el certificado raíz en /etc/ssl/certs/ y hemos puesto el enlace con el hash, funcionará sin problemas:

 # wget https://desarrollo.vicente-navarro.com/blog/wp/wp-login.php--2009-02-22 08:41:25--  https://desarrollo.vicente-navarro.com/blog/wp/wp-login.php
Resolving desarrollo.vicente-navarro.com... 127.0.0.1
Connecting to desarrollo.vicente-navarro.com|127.0.0.1|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 3111 (3.0K) [text/html]
Saving to: `wp-login.php'

100%[======================================>] 3,111       --.-K/s   in 0.001s  

2009-02-22 08:41:27 (4.32 MB/s) - `wp-login.php' saved [3111/3111]

En otro caso, fallará:

$ wget https://desarrollo.vicente-navarro.com/blog/wp/wp-login.php
--2009-02-22 07:59:01--  https://desarrollo.vicente-navarro.com/blog/wp/wp-login.php
Resolving desarrollo.vicente-navarro.com... 192.168.4.35
Connecting to desarrollo.vicente-navarro.com|192.168.4.35|:443... connected.
ERROR: cannot verify desarrollo.vicente-navarro.com's certificate, issued by `/C=ES/ST=Spain/O=Super Coco Inc./OU=Barrio Sesamo/CN=Super Coco Certification Authority/emailAddress=supercoco@barriosesamo.com':
  Unable to locally verify the issuer's authority.
To connect to desarrollo.vicente-navarro.com insecurely, use `--no-check-certificate'.
Unable to establish SSL connection.

por lo que le podríamos pasarle el certificado con la opción --ca-certificate:

$ wget --ca-certificate=cacert.pem https://desarrollo.vicente-navarro.com/blog/wp/wp-login.php
--2009-02-22 07:58:53--  https://desarrollo.vicente-navarro.com/blog/wp/wp-login.php
Resolving desarrollo.vicente-navarro.com... 192.168.4.35
Connecting to desarrollo.vicente-navarro.com|192.168.4.35|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 3111 (3.0K) [text/html]
Saving to: `wp-login.php'

100%[======================================>] 3,111       --.-K/s   in 0s      

2009-02-22 07:58:55 (16.4 MB/s) - `wp-login.php' saved [3111/3111]

Enlaces adicionales

:wq

Entradas relacionadas

8 Comentarios a “Crear los certificados SSL para nuestro servidor web HTTPS con Apache, OpenSSL y Debian Lenny”

  • robert dice:

    Para no tener que dejar la parte privada sin contraseña se puede usar el verbo de apache sslpassphrasedialog; le puedes decir que la contraseña la obtenga del resultado de un ejecutable, de esta forma:
    SSLPassPhraseDialog exec:/bla/blabla/ejecutable

    El ejecutable lo único que tiene que hacer es retornar la contraseña por el stdout, puede ser tan facil o dificil como necesites, pero valdría con que contenga algo como:

    #!/bin/sh
    echo "esta_es_Mi_contraseña_supersegura"

    Por supuesto que ese ejecutable debería estar protegido y esas cosillas.

Trackbacks y pingbacks:

Tema LHYLE09, creado por Vicente Navarro