Crear certificados digitales con OpenSSL

Cuando queremos programar o usar alguna aplicación que requiera autenticación y encriptación podemos hacer uso de certificados digitales. Para obtenerlo podemos hacer uso de un certificado obtenido mediante VeriSign, DNI electrónico o crear nosotros uno mismo.

En esta entrada de blog vamos a hacer esta última opción, que aunque no podrá ser verificado por ninguna Autoridad Certificadora (CA), nos servirá perfectamente mientras realizamos el desarrollo.

Antes de empezar, vamos a suponer que tenemos claros los conceptos del certificado digital, tales como:

También será necesario tener claro algunos conceptos muy básicos de Linux como moverse por archivos, permisos, edición, etc.

Instalar OpenSSL

Para empezar, necesitaremos OpenSSL instalado a ser posible la versión más actualizada posible, ya que si no, puede ser que alguno de los pasos no funcione correctamente.

En Windows lo descargaremos y descomprimiremos y en Linux para Ubuntu/Debian:

sudo apt-get install openssl

o para RedHat / CentOS:

yum install openssl

lo tendremos instalado.

Crear autoridad certificadora de certificados X.509

Prepararemos el entorno:

cd $HOME
mkdir CA
cd CA
mkdir certificados
mkdir privado
echo '01' > contador
touch certindex

Ahora generaremos el archivo de configuración OpenSSL

nano openssl.cnf

El contenido debería ser algo así:

# -----------------------
# Configuración inicial
# -----------------------

dir           = .    # Directorio de trabajo

[ ca ]
default_ca    = CA_default

[ CA_default ]
serial        = $dir/contador          # Contador de números de serie
database      = $dir/certindex         # Listado de certificados
new_certs_dir = $dir/certificados      # Directorio para los certificados generados
certificate   = $dir/cacert.pem        # Certificado raíz
private_key   = $dir/privado/cakey.pem # Clave privada del certificado raíz
default_md    = sha1                   # Digest usado
preserve      = no                     # Preserva el orden de los campos del DN
nameopt       = default_ca             # Muestra detalles del certificado
certopt       = default_ca             # Muestra detalles del certificado
policy        = policy_match           # Indica si los campos obligatorios  y/o
                                       # opcionales deben ser iguales al 
                                       # certificado raíz

# Política de recolección de datos frente al raíz
[ policy_match ]
countryName                 = match        
stateOrProvinceName         = match          
organizationName            = match
organizationalUnitName      = optional      
commonName                  = supplied     
emailAddress                = optional

# Configuración de certificados
[ req ]
default_bits       = 2048           # Tamaño de la clave en bits
default_keyfile    = key.pem        # Fichero de la clave privada
default_md         = sha1           # Digest
string_mask        = nombstr        # Caracteres permitidos en la clave
distinguished_name = req_distinguished_name  # Sección para el nombre DN
req_extensions     = v3_req         # Sección con mas extensiones que se 
                                    # añaden a la petición del 
                                    # certificado

# Distinguished Name. Datos públicos del certificado X.509 que identifican al propietario.
[ req_distinguished_name ]
0.organizationName          = Nombre de la organización
0.organizationName_default  = Imaginanet
organizationalUnitName      = Departamento
emailAddress                = Correo electrónico
emailAddress_max            = 40
localityName                = Ciudad
stateOrProvinceName         = Estado o provincia
countryName                 = Código ISO del pais (dos letras)
countryName_default         = ES
countryName_min             = 2
countryName_max             = 2
commonName                  = Nombre común (nombre del host o IP)
commonName_max              = 64

# Si se indica la opcion -x509 indica que se trata de un certificado CA raíz
# con autoridad para firmar o revocar otros certificados
[ v3_ca ]
basicConstraints       = CA:TRUE  
                                 
subjectKeyIdentifier   = hash     
authorityKeyIdentifier = keyid:always,issuer:always  

[ v3_req ]
basicConstraints            = CA:FALSE
subjectKeyIdentifier        = hash 

Finalmente ejecutamos
openssl req -new -x509 -extensions v3_ca -keyout privado/cakey.pem  -out cacert.pem -days 3650 -config ./openssl.cnf

Creando un certificado digital X.509 en base a nuestra autoridad certificadora

openssl req -new -nodes -out imaginanet-cert.pem -config ./openssl.cnf

openssl ca -out certificado-imaginanet.pem -config ./openssl.cnf -days 3650  -infiles imaginanet-cert.pem

Donde el archivo imaginanet-cert.pem corresponde a nuestra clave privada y certificado-imaginanet.pem a la pública.

Utilidades

No debemos olvidar que los certificados generados no serán validos en un entorno real de producción ya que nuestra CA no será reconocida por los navegadores o el KeyStore de Java, pero si que nos vendrá bien como entorno de desarrollo para:

  • Poner un servidor web en modo seguro HTTPS
  • Realizar firmas sobre ficheros o correos mediante cualquier lenguaje de programación

Añadiendo la autoridad certificadora y nuestro certificado digital a nuestro navegador: Firefox

Supongamos que hemos puesto en marcha nuestro servidor web Apache con HTTPS y el certificado digital creado. Para que el navegador nos confirme que es una página válida deberemos añadir la autoridad certificadora a la lista de autoridades certificadoras válidas. En el caso de Firefox:

Editar -> Preferencias -> Avanzado -> Cifrado -> Ver certificados -> Autoridades -> Importar

y seleccionaremos el archivo cacert.pem

Si por el contrario quisiéramos firmar digitalmente con el certificado creado, deberemos añadir el certificado digital yendo a:

Editar -> Preferencias -> Avanzado -> Cifrado -> Ver certificados -> Sus certificados -> Importar

y seleccionar la clave privada imaginanet-cert.pem e introducir la contraseña para ser guardada en el KeyStore de Firefox.

Todo documento firmado con este certificado será no válido ya que el servidor que lo firme no reconocerá a la autoridad certificadora, pero podemos añadir dicho certificado al KeyStore del lado del servidor, cosa que veremos en próximas entradas del blog.

Convertir certificados .pem / .cert (X.509) a .pfx (PKCS12)

En ocasiones es necesario el uso de certificados en formato PKCS12 de extensión PFX, como por ejemplo para la librería iText para Java / C#. Lo podemos hacer mediante el siguiente comando con OpenSSL 0.9.8k (si tenemos una versión inferior deberemos actualizar ya que no funciona en todas las aplicaciones el fichero generado):

openssl pkcs12 -inkey private_key.pem -in public_cert.cert -export -out cert.pfx

Referencias

Parte de este artículo se ha basado en http://www.linuxtotal.com.mx/ssl_apache.html

Más información:

Comentarios

Comentario de roneypc - 17 de Febrero de 2014 - 20:44
Todo muy bien, funciona, hasta la penúltima línea. La parte de convertir certificados .pem a pkcs12 no funciona.¿Qué ejemplo has usado? openssl pkcs12 -inkey private_key.pem -in public_cert.cert -export -out cert.pfx ??? Podrías usar los mismos nombres de los ejemplos de arriba? imaginanet, cacert, etc.. No has generado ningun fichero ".cert", sólo existen ".pem" ¿a cuál te refieres? Gracias.
Comentario de pablo - 19 de Febrero de 2014 - 17:22
Tengo la misma duda, no se cual es el "public_cert.cert". Por favor tu explicación. Mil gracias.
Comentario de Ericka - 13 de Febrero de 2016 - 18:06
Muy buen post, pero comparto la inquietud de mis compa;eros en cuanto a la conversion ed la extencion
Comentario de Bet - 31 de Enero de 2018 - 04:36
De la misma manera, dice que no encuentra public_cert.cert, me imagino que es el certificado, pero si se lo cambio, me dice error en private_key.pem
Comentario de Betza - 31 de Enero de 2018 - 05:20
Solucionado!!!! Lo único que tienen que hacer es cambiar el nombre de la llave privada y el certificado ej: cambiar la llave publica private_key.pem por key.pem tambien cambiar el nombre del certificado: public_cert.cert por el nombre del certificado. Tambien cabe mencionar que antes de convertir el certificado, falta el autofirmado ja!
Ha habido un error en el envío
Comentario enviado. Será revisado por la moderación antes de ser publicado.

Deja tu comentario

Tu nombre:
Tu email:
Tu comentario: