En criptografía una autoridad de certificación, certificadora o certificante (AC o CA por sus siglas en inglés Certification Authority) es una entidad de confianza, responsable de emitir y revocar los certificados digitales o certificados, utilizados en la firma electrónica, para lo cual se emplea la criptografía de clave pública. Jurídicamente es un caso particular de Prestador de Servicios de Certificación.

La Autoridad de Certificación, por sí misma o mediante la intervención de una Autoridad de Registro, verifica la identidad del solicitante de un certificado antes de su expedición o, en caso de certificados expedidos con la condición de revocados, elimina la revocación de los certificados al comprobar dicha identidad. Los certificados son documentos que recogen ciertos datos de su titular y su clave pública y están firmados electrónicamente por la Autoridad de Certificación utilizando su clave privada.

Certificado raiz

Preparación del escenario

Creamos el directorio raíz mkdir /root/ca y la estructura de directorios. Los archivos index.txt y serial actúan como una base de datos de archivos planos para realizar un seguimiento de los certificados firmados.

# cd /root/ca
# mkdir certs crl newcerts private
# chmod 700 private
# touch index.txt
# echo 1000 > serial

Creación fichero de configuración openssl.cnf

Debemos crear un fichero de configuración /root/ca/openssl.cnf el cual vamos a rellenar con lo siguiente:

# OpenSSL root CA configuration file.
# Copy to `/root/ca/openssl.cnf`.

[ ca ]
# `man ca`
default_ca = CA_default

[ CA_default ]
# Directory and file locations.
dir               = /root/ca
certs             = $dir/certs
crl_dir           = $dir/crl
new_certs_dir     = $dir/newcerts
database          = $dir/index.txt
serial            = $dir/serial
RANDFILE          = $dir/private/.rand

# The root key and root certificate.
private_key       = $dir/private/ca.key.pem
certificate       = $dir/certs/ca.cert.pem

# For certificate revocation lists.
crlnumber         = $dir/crlnumber
crl               = $dir/crl/ca.crl.pem
crl_extensions    = crl_ext
default_crl_days  = 30

# SHA-1 is deprecated, so use SHA-2 instead.
default_md        = sha256

name_opt          = ca_default
cert_opt          = ca_default
default_days      = 375
preserve          = no
policy            = policy_strict

[ policy_strict ]
# The root CA should only sign intermediate certificates that match.
# See the POLICY FORMAT section of `man ca`.
countryName             = match
stateOrProvinceName     = match
organizationName        = match
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

[ policy_loose ]
# Allow the intermediate CA to sign a more diverse range of certificates.
# See the POLICY FORMAT section of the `ca` man page.
countryName             = optional
stateOrProvinceName     = optional
localityName            = optional
organizationName        = optional
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

[ req ]
# Options for the `req` tool (`man req`).
default_bits        = 2048
distinguished_name  = req_distinguished_name
string_mask         = utf8only

# SHA-1 is deprecated, so use SHA-2 instead.
default_md          = sha256

# Extension to add when the -x509 option is used.
x509_extensions     = v3_ca

[ req_distinguished_name ]
# See <https://en.wikipedia.org/wiki/Certificate_signing_request>.
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

# Optionally, specify some defaults.
countryName_default             = GB
stateOrProvinceName_default     = England
localityName_default            =
0.organizationName_default      = Alice Ltd
organizationalUnitName_default  =
emailAddress_default            =

[ v3_ca ]
# Extensions for a typical CA (`man x509v3_config`).
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true
keyUsage = critical, digitalSignature, cRLSign, keyCertSign

[ v3_intermediate_ca ]
# Extensions for a typical intermediate CA (`man x509v3_config`).
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true, pathlen:0
keyUsage = critical, digitalSignature, cRLSign, keyCertSign

[ usr_cert ]
# Extensions for client certificates (`man x509v3_config`).
basicConstraints = CA:FALSE
nsCertType = client, email
nsComment = "OpenSSL Generated Client Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, emailProtection

[ server_cert ]
# Extensions for server certificates (`man x509v3_config`).
basicConstraints = CA:FALSE
nsCertType = server
nsComment = "OpenSSL Generated Server Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth

[ crl_ext ]
# Extension for CRLs (`man x509v3_config`).
authorityKeyIdentifier=keyid:always

[ ocsp ]
# Extension for OCSP signing certificates (`man ocsp`).
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, digitalSignature
extendedKeyUsage = critical, OCSPSigning

Creamos clave privada para la entidad certificadora

Ahora vamos a crear el certificado para la entidad certificadora primero creamos la clave privada

# cd /root/ca
# openssl genrsa -aes256 -out private/ca.key.pem 4096

Enter pass phrase for ca.key.pem: *********
Verifying - Enter pass phrase for ca.key.pem: *********

# chmod 400 private/ca.key.pem

Creamos certificado raiz de la entidad certificadora

Utilizamos la clave raíz ca.key.pem para crear un certificado raíz ca.cert.pem. Proporcione al certificado raíz una fecha de caducidad larga, como veinte años. Una vez que expire el certificado raíz, todos los certificados firmados por la entidad emisora ​​serán inválidos.

# cd /root/ca
# openssl req -config openssl.cnf \
      -key private/ca.key.pem \
      -new -x509 -days 7300 -sha256 -extensions v3_ca \
      -out certs/ca.cert.pem

Enter pass phrase for ca.key.pem: secretpassword
You are about to be asked to enter information that will be incorporated
into your certificate request.
-----
Country Name (2 letter code) [XX]:ES
State or Province Name []:Sevilla
Locality Name []: 
Organization Name []:[Nombre de tu organizacion]
Organizational Unit Name []:[Nombre de tu organizacion]
Common Name []:[Nombre de tu organizacion]
Email Address []:[Correo electronico]

# chmod 444 certs/ca.cert.pem

Creamos un certificado intermedio

El motivo principal del certificado intermedio es tener mas seguridad. Si la clave intermedia está comprometida, la entidad emisora ​​de certificados raíz puede revocar el certificado intermedio y crear un nuevo par criptográfico intermedio.

Preparar el escenario

Creamos el directorio raíz mkdir /root/ca/intermediate y la estructura de directorios. Los archivos index.txt y serial actúan como una base de datos de archivos planos para realizar un seguimiento de los certificados firmados.

# cd /root/ca/intermediate
# mkdir certs crl csr newcerts private
# chmod 700 private
# touch index.txt
# echo 1000 > serial

Creación fichero de configuración openssl.cnf

Al igual que en el apartado anterior vamos a crear un fichero de configuracion /root/ca/intermediate/openssl.cnf

# OpenSSL intermediate CA configuration file.
# Copy to `/root/ca/intermediate/openssl.cnf`.

[ ca ]
# `man ca`
default_ca = CA_default

[ CA_default ]
# Directory and file locations.
dir               = /root/ca/intermediate
certs             = $dir/certs
crl_dir           = $dir/crl
new_certs_dir     = $dir/newcerts
database          = $dir/index.txt
serial            = $dir/serial
RANDFILE          = $dir/private/.rand

# The root key and root certificate.
private_key       = $dir/private/intermediate.key.pem
certificate       = $dir/certs/intermediate.cert.pem

# For certificate revocation lists.
crlnumber         = $dir/crlnumber
crl               = $dir/crl/intermediate.crl.pem
crl_extensions    = crl_ext
default_crl_days  = 30

# SHA-1 is deprecated, so use SHA-2 instead.
default_md        = sha256

name_opt          = ca_default
cert_opt          = ca_default
default_days      = 375
preserve          = no
policy            = policy_loose

[ policy_strict ]
# The root CA should only sign intermediate certificates that match.
# See the POLICY FORMAT section of `man ca`.
countryName             = match
stateOrProvinceName     = match
organizationName        = match
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

[ policy_loose ]
# Allow the intermediate CA to sign a more diverse range of certificates.
# See the POLICY FORMAT section of the `ca` man page.
countryName             = optional
stateOrProvinceName     = optional
localityName            = optional
organizationName        = optional
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

[ req ]
# Options for the `req` tool (`man req`).
default_bits        = 2048
distinguished_name  = req_distinguished_name
string_mask         = utf8only

# SHA-1 is deprecated, so use SHA-2 instead.
default_md          = sha256

# Extension to add when the -x509 option is used.
x509_extensions     = v3_ca

[ req_distinguished_name ]
# See <https://en.wikipedia.org/wiki/Certificate_signing_request>.
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

# Optionally, specify some defaults.
countryName_default             = GB
stateOrProvinceName_default     = England
localityName_default            =
0.organizationName_default      = Alice Ltd
organizationalUnitName_default  =
emailAddress_default            =

[ v3_ca ]
# Extensions for a typical CA (`man x509v3_config`).
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true
keyUsage = critical, digitalSignature, cRLSign, keyCertSign

[ v3_intermediate_ca ]
# Extensions for a typical intermediate CA (`man x509v3_config`).
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true, pathlen:0
keyUsage = critical, digitalSignature, cRLSign, keyCertSign

[ usr_cert ]
# Extensions for client certificates (`man x509v3_config`).
basicConstraints = CA:FALSE
nsCertType = client, email
nsComment = "OpenSSL Generated Client Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, emailProtection

[ server_cert ]
# Extensions for server certificates (`man x509v3_config`).
basicConstraints = CA:FALSE
nsCertType = server
nsComment = "OpenSSL Generated Server Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth

[ crl_ext ]
# Extension for CRLs (`man x509v3_config`).
authorityKeyIdentifier=keyid:always

[ ocsp ]
# Extension for OCSP signing certificates (`man ocsp`).
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, digitalSignature
extendedKeyUsage = critical, OCSPSigning

Se han cambiado cinco opciones en comparación con el archivo de configuración de la CA raíz:

[ CA_default ]
dir             = /root/ca/intermediate
private_key     = $dir/private/intermediate.key.pem
certificate     = $dir/certs/intermediate.cert.pem
crl             = $dir/crl/intermediate.crl.pem
policy          = policy_loose

Crear clave privada intermedia

Cree la clave intermediate.key.pem. Cifrar la clave intermedia con encriptación AES de 256 bits y una contraseña segura.

# cd /root/ca
# openssl genrsa -aes256 \
      -out intermediate/private/intermediate.key.pem 4096

Enter pass phrase for intermediate.key.pem: ********
Verifying - Enter pass phrase for intermediate.key.pem: *******

# chmod 400 intermediate/private/intermediate.key.pem

Crear certificado intermedio

Creamos el certificado intermedio igual que en el apartado anterior:

# cd /root/ca
# openssl req -config intermediate/openssl.cnf -new -sha256 \
      -key intermediate/private/intermediate.key.pem \
      -out intermediate/csr/intermediate.csr.pem

Enter pass phrase for intermediate.key.pem: secretpassword
You are about to be asked to enter information that will be incorporated
into your certificate request.
-----
Country Name (2 letter code) [XX]:ES
State or Province Name []:Sevilla
Locality Name []:
Organization Name []:[Nombre de tu organizacion]
Organizational Unit Name []:[Nombre de tu organizacion]
Common Name []:[Nombre de tu organizacion]
Email Address []:[Correo electronico]

Para crear un certificado intermedio, utilice la entidad emisora ​​raíz con la v3_intermediate_ca para firmar la CSR intermedia. El certificado intermedio debe ser válido por un período más corto que el certificado raíz. Por ejemplo diez años sería razonable.

# cd /root/ca
# openssl ca -config openssl.cnf -extensions v3_intermediate_ca \
      -days 3650 -notext -md sha256 \
      -in intermediate/csr/intermediate.csr.pem \
      -out intermediate/certs/intermediate.cert.pem

Enter pass phrase for ca.key.pem: ********
Sign the certificate? [y/n]: y

# chmod 444 intermediate/certs/intermediate.cert.pem

Para estar seguro de que lo hemos realizado correctamente vamos a comprobar el certificado intermedio:

# openssl verify -CAfile certs/ca.cert.pem \
      intermediate/certs/intermediate.cert.pem

intermediate.cert.pem: OK

Juntar certificado raiz e intermedio

# cat intermediate/certs/intermediate.cert.pem \
      certs/ca.cert.pem > intermediate/certs/ca-chain.cert.pem
# chmod 444 intermediate/certs/ca-chain.cert.pem
Cuidado! Debes tener en cuenta que las peticiones de certificados deben de ser iguales es decir Country Name, State or Province Name, Locality Name, Organization Name, Organizational Unit Name, Common Name, Email Address .

Firmar los certificados de servidor y cliente

Firmaremos certificados utilizando nuestra CA intermedia

Solicitar certificado en el servidor web

Ya tenemos operativa nuestra entidad certificadora. Ahora desde una segunda maquina (una debian en mi caso) que hará la funciones de Servidor Web que va a solicitar un certificado, para ello vamos a crear tambien la estructura anterior:

# cd /root/ca
# mkdir certs crl newcerts private
# chmod 700 private
# touch index.txt
# echo 1000 > serial

Debemos crear un fichero de configuración /root/ca/openssl.cnf el cual vamos a rellenar con lo siguiente:

# OpenSSL root CA configuration file.
# Copy to `/root/ca/openssl.cnf`.

[ ca ]
# `man ca`
default_ca = CA_default

[ CA_default ]
# Directory and file locations.
dir               = /root/ca
certs             = $dir/certs
crl_dir           = $dir/crl
new_certs_dir     = $dir/newcerts
database          = $dir/index.txt
serial            = $dir/serial
RANDFILE          = $dir/private/.rand

# The root key and root certificate.
private_key       = $dir/private/ca.key.pem
certificate       = $dir/certs/ca.cert.pem

# For certificate revocation lists.
crlnumber         = $dir/crlnumber
crl               = $dir/crl/ca.crl.pem
crl_extensions    = crl_ext
default_crl_days  = 30

# SHA-1 is deprecated, so use SHA-2 instead.
default_md        = sha256

name_opt          = ca_default
cert_opt          = ca_default
default_days      = 375
preserve          = no
policy            = policy_strict

[ policy_strict ]
# The root CA should only sign intermediate certificates that match.
# See the POLICY FORMAT section of `man ca`.
countryName             = match
stateOrProvinceName     = match
organizationName        = match
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

[ policy_loose ]
# Allow the intermediate CA to sign a more diverse range of certificates.
# See the POLICY FORMAT section of the `ca` man page.
countryName             = optional
stateOrProvinceName     = optional
localityName            = optional
organizationName        = optional
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

[ req ]
# Options for the `req` tool (`man req`).
default_bits        = 2048
distinguished_name  = req_distinguished_name
string_mask         = utf8only

# SHA-1 is deprecated, so use SHA-2 instead.
default_md          = sha256

# Extension to add when the -x509 option is used.
x509_extensions     = v3_ca

[ req_distinguished_name ]
# See <https://en.wikipedia.org/wiki/Certificate_signing_request>.
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

# Optionally, specify some defaults.
countryName_default             = GB
stateOrProvinceName_default     = England
localityName_default            =
0.organizationName_default      = Alice Ltd
organizationalUnitName_default  =
emailAddress_default            =

[ v3_ca ]
# Extensions for a typical CA (`man x509v3_config`).
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true
keyUsage = critical, digitalSignature, cRLSign, keyCertSign

[ v3_intermediate_ca ]
# Extensions for a typical intermediate CA (`man x509v3_config`).
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true, pathlen:0
keyUsage = critical, digitalSignature, cRLSign, keyCertSign

[ usr_cert ]
# Extensions for client certificates (`man x509v3_config`).
basicConstraints = CA:FALSE
nsCertType = client, email
nsComment = "OpenSSL Generated Client Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, emailProtection

[ server_cert ]
# Extensions for server certificates (`man x509v3_config`).
basicConstraints = CA:FALSE
nsCertType = server
nsComment = "OpenSSL Generated Server Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth

[ crl_ext ]
# Extension for CRLs (`man x509v3_config`).
authorityKeyIdentifier=keyid:always

[ ocsp ]
# Extension for OCSP signing certificates (`man ocsp`).
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, digitalSignature
extendedKeyUsage = critical, OCSPSigning

Una vez creado dicho fichero, generamos la clave privada:

# cd /root/ca
# openssl genrsa -aes256 -out private/prueba.key.pem 4096

Enter pass phrase for ca.key.pem: *********
Verifying - Enter pass phrase for ca.key.pem: *********

# chmod 400 private/ca.key.pem

Una vez tengo la clave privada, ya puedo generar la petición de certificado openssl req -new -key private/prueba.key.pem -out csr/prueba.csr.pem:

Y lo mandamos al servidor mediante scp.

Info! Los nombre de los ficheros .crs, .pem, .crt y los datos añadido son un ejemplo pueden variar según nos nuestra preferencias.

Generar certificado desde entidad con autoridad

El siguiente paso es mandar al administrador de la entidad certificadora el archivo .csr , una vez se reciba, generaremos el certificado de la siguiente manera:

# cd /root/ca
# openssl ca -config intermediate/openssl.cnf \
      -extensions server_cert -days 375 -notext -md sha256 \
      -in intermediate/csr/prueba.csr.pem \
      -out intermediate/certs/prueba.cert.pem
      
# chmod 444 intermediate/certs/prueba.cert.pem

Info! En este caso voy a transferirlo por «scp» pero podéis usar el método que prefirais. Tambien puedes enviar un correo cifrado como explico en esta entrada Firmar y cifrar un correo con GPG
Info! El segundo parámetro .key debe ser la clave privada de nuestro servidor para poder firmar el certificado.

.

Envío al servidor web y comprobar se encuentra nuestra clave privada

Ahora deberíamos enviar el certificado del servidor,el certificado intermedio y el certificado raiz, al que será nuestro servidor web y lo deberíamos copiar en /etc/ssl/certs. Así mismo comprobamos la presencia de la clave privada del servidor, para ello volvemos a utilizar scp y una vez en el Servidor Web lo copiamos a la carpeta /etc/ssl/certs.

root@rebeca:~/ca# scp intermediate/certs/prueba.cert.pem intermediate/certs/intermediate.cert.pem certs/ca.cert.pem usuario@172.22.10.215:/home/usuario
root@debian:/home/usuario# cp ca.cert.pem prueba.cert.pem intermediate.cert.pem /etc/ssl/certs/

Comprobamos que mi clave privada y el certificado son iguales

Para ello vamos a utilizar dos comandos uno para comprobar la clave privada openssl rsa -in /root/ca/private/prueba.key.pem -noout -modulus y el certificado firmado openssl x509 -in prueba.cert.pem -noout -modulus

Activar modulo SSL en Apache

Luego vamos a habilitar el módulo de SSL en Apache sudo a2enmod ssl:

Crear un virtual host para SSL

Creamos un virtual host sudo nano /etc/apache2/sites-available/default-ssl y vamos a añadir el siguiente contenido:

<IfModule mod_ssl.c>
  <VirtualHost _default_:443>
    ServerName www.prueba.com
    ServerAdmin webmaster@localhost
    DocumentRoot /var/www
    <Directory />
        Options FollowSymLinks
        AllowOverride None
    </Directory>
    <Directory /var/www/>
      Options -Indexes FollowSymLinks MultiViews
      AllowOverride None
      Order allow,deny
      allow from all
    </Directory>
    ErrorLog ${APACHE_LOG_DIR}/error.log
    LogLevel warn
    CustomLog ${APACHE_LOG_DIR}/ssl_access.log combined
    SSLEngine on
    SSLCertificateKeyFile /root/ca/private/prueba.key.pem
    SSLCertificateFile /etc/ssl/certs/prueba.cert.pem
    #SSLCACertificateFile /etc/ssl/certs/bundle.crt
    BrowserMatch "MSIE [2-6]" \
      nokeepalive ssl-unclean-shutdown \
      downgrade-1.0 force-response-1.0
    # MSIE 7 and newer should be able to use keepalive
    BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown
  </VirtualHost>
</IfModule>
Info! Recuerda cambiar el «ServerName» al que tu prefieras.

Una vez configurado el certificado en el archivo virtual host, vamos a habilitarlo sudo a2ensite default-ssl:

Para que la configuración tenga efecto, vamos a cargarla nuevamente sudo service apache2 reload.

Bien, ahora tienen un certificado SSL configurado y funcionando.

Si en el paso anterior hay un error, puede encontrar el porque del error en el archivo /var/log/apache2/error.log.

Verificamos el certificado SSL desde un navegador

Una vez todo esta configurado, nos resta verificar la url desde nuestro navegador. Para esto vamos a escribir https://[Dominio].

La primera vez que intentemos acceder nos va a dar una alerta de que el certificado no es de confianza, esto es porque no hemos añadido o una excepcion sobre esa pagina o el certificado al navegador.

La solución es dar clic en Entiendo riesgo y luego en Anadir una excepcion con eso añadiremos esa pagina a nuestra lista de excepciones.

Debemos hacer clic en Confirmar excepcion de seguridad y ya la tendremos añadido, por lo tanto la comunicacion con tu dominio es segura (siempre y cuando la conexión se mantenga bajo https://), podrás observar el candado en verde y cerrado en la barra de navegación que lo confirma.

Y ya podemos observar que podemos acceder a la pagina de forma segura.