OpenSSL es un conjunto de utilidades y librerías que implementan diferentes rutinas criptográficas que ayudan a implementar todo tipo de protocolos seguros. Una de las funciones incluidas nos permite crear una autoridad de certificación o CA: una entidad en la que confiamos que puede emitir o revocar certificados que se usan para tener una comunicación segura.
En esta entrada pretendo crea una CA que nos permita generar certificados que puedan ser usardos para establecer conexiones https o conexiones cifradas con utilidades como socat. Esta CA estará autofirmada y será necesario que su certificado raíz esté disponible para aquellos programas que deseen comprobar la validez de un certificado firmado por la misma. Existen paquetes como easy rsa para quien no quiera hacer estos pasos manualmente.
Crear la autoridad de certificación
Para crear nuestra CA basta con bajarse el fichero de configuración config.cnf y seguir los siguientes pasos que se dan a continuación. En la última parte del artículo se hace un recorrido por todas las opciones de dicho fichero para comprender su funcionamiento.
- Crear la estructura de ficheros
mkdir /Users/terron/prog/ca
mkdir /Users/terron/prog/ca/{certreqs,crls,private,certsdb}
- Crear el fichero de configuración y el fichero de base de datos.
cd /Users/terron/prog/ca
wget -O config.cnf https://sites.google.com/site/underdarktales/home/propios/config.cnf?attredirects=0&d=1
touch index.txt
- Crear la clave privada y el CSR de la autoridad de certificación. El sistema pedirá el valor de ciertos atributos del certificado que están definidos en el fichero de configuración, en la sección de la política - ver al final del artículo -
cd /Users/terron/prog/ca
openssl req -new -nodes -newkey rsa:4096 -keyout private/cakey.pem -out careq.pem -config config.cnf
Las opciones que se le pasa a openssl req son las siguientes:
- -config Usa el fichero de configuración config.cnf
- -new Crea una nueva petición de CSR.
- -newkey Crea una nueva clave RSA. En este caso de 4096 bits de longitud.
- -nodes Indica que no se debe cifrar la clave privada. Recordar que para mantener la integridad de la CA, es necesario proteger esta clave al máximo.
- -keyout Ruta al fichero donde se escribirá la clave privada. Se almacenará en private/cakey.pem
- -out Ruta al fichero donde se escribirá el CSR. Se almacenará en careq.pem
- Crear el certificado autofirmado e iniciar el número de serie. Este es el certificado que debe de distribuirse a aquellos programas que quiera verificar la autenticidad de un certificado firmado por nuestra CA.
cd /Users/terron/prog/ca
openssl ca -create_serial -out cacert.pem -days 3650 -keyfile private/cakey.pem -selfsign -extensions v3_ca -config ./config.cnf -infiles careq.pem
Con esta llamada a openssl ca se generará el fichero cacert.pem que será el que se deba de distribuir como certificado raíz de nuestra CA. Los parámetros con los que se llamarán serán los siguientes:
- -config Ruta al fichero de configuración. En nuestro caso config.cnf.
- -create_serial Esta opción creará el fichero serial.txt y creará un número aleatorio de 128 bits en hexadecimal que se irá incrementando con cada certificado firmado.
- -out Ruta donde se depositará el certificado firmado por la CA. Además, creará una copia en el directorio certsdb.
- -days Número de días en las que será válido el certificado desde el momento en que se firme. En este caso, al ser la raíz de la CA, 10 años.
- -keyfile Clave privada de la CA que se va a usar para generar el certificado firmado.
- -selfsign Indica que se quiere un certificado autofirmado. Esto se hace para generar el certificado raíz de la CA.
- -extensions Utiliza la extensión de certificado X.509 definida en el fichero de configuración. En este caso se utiliza la extensión llamada v3_ca y define los atributos necesarios para que el certificado generado sea el raíz de una CA.
Generar un certificado firmado por nuestra CA
Para generar un certificado firmado por nuestra CA es necesario dar los siguientes pasos:
- Generar una clave privada y un CSR. Es importante, en el caso de querer usar este certificado para https que el campo CN que nos pregunta el comando coincida con el nombre del host o en su caso con la dirección IP, sino no funcionará.
openssl req -new -nodes -newkey rsa:4096 -keyout server.key.pem -out server.req.pem -config config.cnf
- Usar el CSR (fichero server.req.pem) generado en el paso anterior para generar nuestro certificado firmado por nuestra CA. Esta orden nos mostrará los atributos del certificdado que está apunto de firmar para que confirmemos la operación.
cd /Users/terron/prog/ca
openssl ca -config config.cnf -days 365 -keyfile private/cakey.pem -extensions v3_req -in server.req.pem -out server.cert.pem
Las opciones son similares al caso del certificado raíz, pero usando otras extensiones para el certificado X.509
Restricciones y posibles problemas
- La base de datos de texto que usa openssl ca para guardar los certificados firmados es crítica. Si se pierde peude haber problemas.
- No hay ningún tipo de soporte para concurrencia en openssl ca a la hora de firmar los certificados.
El fichero de configuración
Esta sección contiene una descripción detallada del fichero de configuración config.cnf usado como ejemplo en los pasos anteriores. Este fichero está compuesto de secciones que se utilizan en función de la utilidad de OpenSSL que se llame. Nosotros vamos a usar openssl req y openssl ca para la generación de la autoridad de certificación.
La sección de ca
La estructura de directorio que se va a usar es la siguiente. ROOT indica cual es el directorio raíz donde va a residir los ficheros de nuestra autoridad de certificación.
ROOT
certsdb
private
certreqs
crls
En el fichero de configuración se va a definir en primer lugar cuales son las opciones que se van a usar. En primer lugar vamos a definir la sección que se va a usar por defecto para defecto para generar la autoridad de certificación.
[ ca ]
default_ca = CA_default
[ CA_default ]
dir = /Users/terron/prog/ca
database = $dir/index.txt
new_certs_dir = $dir/certsdb
certificate = $dir/cacert.pem
serial = $dir/serial
private_key = $dir/private/cakey.pem
RANDFILE = $dir/private/.rand
default_days = 365
default_crl_days = 30
default_md = sha256
policy = policy_any
email_in_dn = no
name_opt = ca_default
cert_opt = ca_default
copy_extensions = none
[ policy_any ]
countryName = supplied
stateOrProvinceName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
Esta primera sección del fichero config.cnf configura el comportamiento del comando openssl ca. Cuando se llame a dicho comando, pasándole la opción -config config.cnf buscar la sección [ ca ]. En dicha sección le hemos dicho, que por defecto, utilice la sección [ CA_default] la cual configura una serie de propiedades de la autoridad de certificación que se está creando.
En primer lugar, se definen una serie de rutas que se van a usar para almacenar los diferentes ficheros y directorios necesarios para el funcionamiento de la autoridad de certificación. Se va a referenciar a partir de la ruta raíz de la autoridad que está definida en la variable dir y en el ejemplo anterior es /Users/terron/prog/ca. Cuando openssl cuando carga el fichero de configuración realizará las sustituciones de variables necesarias por nosotros. Por ejemplo, en nuestro caso $dir/index.txt pasa a ser /Users/terron/prog/ca/index.txt.
Los parámetros que se configuran en esta sección [ Ca_default ]
- database Configura la ruta hacía la base de datos de certificados. Este parámetro es obligatorio que exista y el fichero debe de existir cuando se empieza a usar la autoridad de certificación. Puede crearse con touch. Se puede especificar la ruta desde la línea de comandos con -database.
- new_certs_dir Configura la ruta al directorio donde se almacenarán los nuevos certificados firmados por la autoridad de certificación. Este parámetro es obligatorio. Se puede tambiér especificar desde la línea de comandos con -outdir.
- certificate Ruta hacía el certificado raíz de la autoridad de certificación. Es obligatorio y también puede especificarse desde la línea de comandos con -cert.
- serial Contiene el siguiente número de serie en hexadecimal para usar en el certificado. Normalmente, en los ejemplos que he visto en Internet se solía configurar con 01, pero es mejor usar una opción cuando se crea el certificado raíz que lo autogenere.Este parámetro es obligatorio.
- private_key Esta es la clave privada de la autoridad de certificación. De su seguridad depende la integridad de todo el proceso de la autoridad de certificación.
- RANDFILE Ruta a un fichero usado para leer y escribir semillas que sirvan para la generación de números aleatorios.
- default_days Número de días en los que será válido un certificado. También puede especificarse con ayuda de la opción de línea de comandos -days.
- default_crl_days Número de días hasta que se publique la siguiente CRL
- default_md Algoritmo de huella digital que se utilizará en los certificados y en la lista de revocación de los mismos. Se puede pasar con la línea de comandos con la opción -md. Es obligatoria.
- policy Configura la sección donde se define la política que va a usar la autoridad de certificación para verificar un certificado. Esta política define qué campos deben de estar presentes y cuales deben de coincidir. Se puede pasar en la línea de comandos con -policy y es obligatoria su definición.
- email_in_dn Si este campo no está presente o vale yes el campo email, se copiará al . Está configurado para que no se copie.
- name_opt, cert_opt Estos dos campos controla los campos que se muestran cuando se pide la verificación de un certificado . Existen varios campos, pero lo razonable es dejar el campo ca_default.
- copy_extensions Controla que hacer con las extensiones que estén presente en las CSR. Si el valor es none , no se copiará ninguna de las extensiones que vengan presenten en el CSR, copy hará que se copia toda extensión que no esté en el certificado destino y copyall copia todas las extensiones del CSR. Hay que tener especial cuidado al usar las opciones copy y copyall porque puede suponer un riesgo de seguridad.
En este fragmento de fichero de configuración se ha definido una política, policy_any. La política corresponde a una serie de campos identificados por su DN. Estos campos tienen tres posibles valores:
- match El campo debe de existir en el certificado y debe de coincidir con el mismo de la autoridad de certificación.
- supplied El campo debe de existir.
- optional El campo puede existir.
Cualquier campo que no esté especificado en la política será descartado sin advertencia. En nuestro ejemplo se ha definido una política que tiene seis campos de los cuales dos son obligatorios y deben de estar presentes. El resto son opcionales.
La sección req
El comando openssl req se controla a través de las sección [ req ] del fichero de configuración. Este comando es el encargado de generar peticiones para que la autoridad de certificación nos la firme. También es el encargado de generar certificados autofirmados para usar en nuestras propias autoridades de certificación. El fragmento del fichero de configuración que se utiliza es el siguiente:
[ req ]
default_bits = 4096
default_md = sha256
prompt = yes
x509_extensions = v3_req
distinguished_name = req_distinguished_name
string_mask = utf8only
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = keyEncipherment, dataEncipherment
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
stateOrProvinceName = State or Province Name
localityName = Locality Name
0.organizationName = Organization Name
organizationalUnitName = Organizational Unit Name
commonName = Common Name
emailAddress = Email Address
countryName_default = ES
stateOrProvinceName_default = Madrid
localityName_default =
0.organizationName_default = Testing OpenSSL S.L.
Los paramétros de configuración de la sección anterior define:
- default_bits Número de bits por defecto - si no se especifica otra cosa - que tendrán la clave privada de los certificados que se generen.
- default_md Algoritmo de huella digital que se utilizará por defecto.
- prompt Si vale no, cogerá los valores por defecto de los campos que utilice el certificado del fichero de configuración. En nuestro caso vale yes porque queremos que el sistema nos pregunte por los campos que se quieren que vayan en el certificado.
- x509_extensions Este campo nos indica una sección dentro del fichero de configuración que se usará cuando se ejecutemos openssl req con la opción -x509. Esta sección especifica una serie de extensiones que se añadirán al certificado. En este caso se está especificando que utilice la sección [ v3_req ].
- distinguished_name Especifica la sección donde se definen los campos por los cuales se preguntará al usuario cuando se genere un CSR o un certificado. En este caso la sección se llama req_distinguished_name.
- string_mask indica que tipo de cadenas de caracteres se va a usar en los campos del certificado. En este caso, se indica que sólo se aceptaran cadenas UTF-8 válidas.
En nuestro caso, la extenciones que se quieren añadir al certificado son
- basicConstraints
- keyUsage
Las sección req_distinguished_name define qué campos van a ir en el certificados. Se pueden definir aquellos que se deseen, siempre que se definan a través de la sección oid_section o oid_file. Existen ya una serie de nombres definidos (con sus correspondientes identificadores) en OpenSSL. En nuestro ejemplo se han definido siete campos, y posteriormente algunos valores por defecto (nombre del campo_default)
La sección para las extensiones de la Autorida de Certificación
Para terminar, es necesario añadir una sección especial en el fichero de configuración donde se definen una serie de extensiones a los certificados X.509 que nos permitirán crear la autoridad [ v3_ca ]:
[ v3_ca ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true
keyUsage = critical, cRLSign, keyCertSign
Esta sección define una serie de restricciones que se usarán para generar el certificado raíz de la autoridad de certificación:
- subjectKeyIdentifier Indica como se debe de calcular el atributo Subject Key Identifier del certificado. Debe de dejarse en el valor de hash.
- authorityKeyIdentifier Este campo configura como debe de calcularse el atributo Authority Key Identifier, que sirve para identificar la autoridad de certificación que ha firmado un certificado. Este campo indica que se usará para indentificar a la misma. En ecaso del ejemplo se usa el keyid - el identificador de la clave de la autoridad de certificación y issuer que hace que se utilicen los campos Subject y el número de serie del certificado de la CA. Aunque esta configuración puede presentar un problema en caso de que tenga que rehacerse la CA con la misma clave privada.
- basicConstraints Este es una extensión que indica que el certificado puede actuar como una autoridad de certificación y permite restringir la longitud de la cadena de certificación. En este caso se le está indicando que el certificado si es una CA y que es crítica, es decir, que sino puede acceder a ella no puede ser procesado
- keyUsage Esta extensión determina cuales son los usos apropiados de la clave de la CA: Al menos debe ser capaz de firmar la lista de revocación de certificados (cRLsign) y los certificados (keyCertSign). En el caso de que esta extensión no esté presente, se permiten todos los usos de las claves.
Referencias