Creación de una PKI en Ubuntu
Una PKI (public key infraestructure) es la solución a un problema denominado "El ataque del hombre en el medio". Puedes averiguar más sobre este problema en nuestro post Infraestructura de Llave Pública. En este post, veremos cómo crear una PKI fácilmente en Ubuntu.
Configuración de una PKI en openssl
Lo primero que debemos hacer es encontrar el archivo de configuración de ejemplo de OpenSSL el cuál podría estar en /etc/ssl/openssl.cnf. Para verificar en dónde está realmente este archivo de configuración podemos ejecutar el siguiente comando.
openssl version -a
Este comando arrojará un resultado similar al siguiente:
OpenSSL 1.1.1 11 Sep 2018
built on: Thu Jun 20 17:36:28 2019 UTC
platform: debian-amd64
options: bn(64,64) rc4(16x,int) des(int) blowfish(ptr)
compiler: gcc -fPIC -pthread -m64 -Wa,--noexecstack -Wall -Wa,--noexecstack -g -O2 -fdebug-prefix-map=/build/openssl-cn9tZy/openssl-1.1.1=. -fstack-protector-strong -Wformat -Werror=format-security -DOPENSSL_USE_NODELETE -DL_ENDIAN -DOPENSSL_PIC -DOPENSSL_CPUID_OBJ -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DKECCAK1600_ASM -DRC4_ASM -DMD5_ASM -DAES_ASM -DVPAES_ASM -DBSAES_ASM -DGHASH_ASM -DECP_NISTZ256_ASM -DX25519_ASM -DPADLOCK_ASM -DPOLY1305_ASM -DNDEBUG -Wdate-time -D_FORTIFY_SOURCE=2
OPENSSLDIR: "/usr/lib/ssl"
ENGINESDIR: "/usr/lib/x86_64-linux-gnu/engines-1.1"
Seeding source: os-specific
La antepenúltima línea en este caso contiene el valor del OPENSSDIR en el cuál estará el archivo de configuración, certificados y otros archivos importantes.
El archivo de configuración de openssl contiene una configuración por defecto. Para efectos de pruebas, no deberías cambiar nada. Sin embargo, si deberás verificar que exista una sección [ ca ] similar a la siguiente:
####################################################################
[ ca ]
default_ca = CA_default # The default ca section
####################################################################
[ CA_default ]
dir = ./demoCA # Where everything is kept
certs = $dir/certs # Where the issued certs are kept
crl_dir = $dir/crl # Where the issued crl are kept
database = $dir/index.txt # database index file.
#unique_subject = no # Set to 'no' to allow creation of
# several certs with same subject.
new_certs_dir = $dir/newcerts # default place for new certs.
certificate = $dir/cacert.pem # The CA certificate
serial = $dir/serial # The current serial number
crlnumber = $dir/crlnumber # the current crl number
# must be commented out to leave a V1 CRL
crl = $dir/crl.pem # The current CRL
private_key = $dir/private/cakey.pem# The private key
Este archivo en primer lugar nos indica que la CA (Autoridad de Certificación) por defecto está definida en la sección CA_default. En esta sección verás que todos los archivos apuntan hacia ./demoCA, en este caso /usr/lib/ssl/demoCA. Sin embargo, esta carpeta así como las que residen dentro de ella no están creadas. Para esto, puedes correr el siguiente comando y crear toda esta estructura de directorios.
mkdir -p demoCA/certs
mkdir demoCA/crl
mkdir demoCA/newcerts
mkdir demoCA/private
También necesitarás crear el archivo de la base de datos de certificados emitidos/revocados y el archivo serial que llevará el consecutivo del último certificado firmado.
touch demoCA/index.txt
echo "C001" > demoCA/serial
Una hecho esto podemos proceder con la creación de la autoridad de certificación.
Creación de la Autoridad de Certificación
Para crear la autoridad de certificación vamos a hacer uso del estándar -x509 que define cómo debe estar codificada la información de un certificado. Todo comienza con la entidad de confianza y un certificado raíz los cuales podemos generar ejecutando el siguiente comando.
openssl req -new -x509 -keyout demoCA/private/cakey.pem -out demoCA/cacert.pem
Este comando creará la llave privada cakey.pem y también el certificado autofirmado cacert.pem el cuál incluye la llave pública de la autoridad de certificación. Debido a que estamos creando un certificado se nos solicitará algunos datos de información similares a los siguientes:
Generating a RSA private key
...................+++++
.................................................................................+++++
writing new private key to '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]:CO
State or Province Name (full name) [Some-State]:Antioquia
Locality Name (eg, city) []:Medellin
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Pleets
Organizational Unit Name (eg, section) []:Tech Dept.
Common Name (e.g. server FQDN or YOUR name) []:https://pleets.org
Email Address []:example@pleets.org
El certificado creado anteriormente es el certificado con el cuál se firmarán los demás certificados (certificados de usuario). También es posible crear autoridades de certificación intermedias que firmarán a su vez los certificados de usuarios (esta configuración no la veremos en este post).
Creación de un certificado de usuario
Antes de realizar esta firma, es decir, que la entidad de confianza nos entregue un certificado, cada usuario debe crear una solicitud de certificado la cuál se puede hacer con el siguiente comando:
openssl req -new -keyout userkey.pem -out usercert-req.pem
Este comando creará la llave privada userkey.pem y el certificado asociado usercert-req.pem. Por supuesto, por ser un certificado el que queremos crear, nuevamente se solicitarán los datos que un certificado debería tener:
Generating a RSA private key
..............................+++++
....................................+++++
writing new private key to 'userkey.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]:CO
State or Province Name (full name) [Some-State]:Antioquia
Locality Name (eg, city) []:Medellin
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Pleets
Organizational Unit Name (eg, section) []:Tech
Common Name (e.g. server FQDN or YOUR name) []:Dario Rivera
Email Address []:example@gmail.com
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
Es importante que veas la diferencia entre un CSR (certificate signing request) y un certificado en sí. Lo que hicimos anteriormente fue crear una solicitud de firma de certificado (CSR) que deberá firmar la CA.
Toda esta información es enviada a la entidad de confianza para certificación, en este caso tu propia CA. Antes de firmar es recomendado revisar nuevamente la información del certificado para ver que todo está correcto. Esto lo puedes hacer con el siguiente comando.
openssl req -text -in usercert-req.pem -noout
Para firmar este certificado con la entidad de confianza debemos utilizar el siguiente comando:
openssl ca -in usercert-req.pem -out usercert.pem
Si todo ha salido bien, la salida de este comando debería ser similar a la siguiente:
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: 49153 (0xc001)
Validity
Not Before: Aug 30 05:38:48 2019 GMT
Not After : Aug 29 05:38:48 2020 GMT
Subject:
countryName = CO
stateOrProvinceName = Antioquia
organizationName = Pleets
organizationalUnitName = Tech
commonName = Dario Rivera
emailAddress = fermius.us@gmail.com
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
Netscape Comment:
OpenSSL Generated Certificate
X509v3 Subject Key Identifier:
89:3D:33:63:A9:76:31:9D:0D:47:11:8D:41:A2:74:C4:EE:19:BB:02
X509v3 Authority Key Identifier:
keyid:09:15:1A:A3:42:C4:79:4E:A0:30:F2:47:C6:5A:C5:55:16:5D:CC:0E
Certificate is to be certified until Aug 29 05:38:48 2020 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
Lo cual indica que se ha generado el certificado usercert.pem de manera correcta. Para convertir este certificado a un formato instalable en el navegador podemos utilizar el siguiente comando:
openssl pkcs12 -export -in usercert.pem -inkey userkey.pem > usercert.p12
Finalmente a modo de test observa que si hubiésemos colocado un organizationName distinto al inicial (Pleets) hubiésemos tenido la siguiente respuesta:
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
The organizationName field is different between
CA certificate (Pleets) and the request (ENCOM)
Lo cual indica que un certificado no puede firmar certificados para organizaciones diferentes a la suya. Espero que hayas aprendido bastante con este post. Hasta la próxima.