4.5.4. Certificados de autenticación

Los certificados digitales permiten tanto identificar al servidor frente al cliente, como al revés. En el primer caso, se usan siempre, ya que es la única forma que tiene el cliente de identificar al servidor; en el segundo, en cambio, el uso es opcional, ya que el cliente puede optar por usar una identificación basada en usuario y contraseña. Analicemos por separado ambos casos.

4.5.4.1. Identificación del servidor

Ya se ha mencionado al anteriormente que para evitar ataques man-in-the-middle mediante la suplantación de la identidad del servidor, éste envía al cliente su clave pública. En la primera conexión aceptar la clave pública de un servidor es un acto de fe, a menos que se haya obtenido esa clave pública de algún modo seguro. Sea como sea, el cliente, por su parte, almacena las claves públicas de todos los servidores a los que se conecta, de modo que si se produce una segunda conexión compara la clave pública que le vuelve a enviar el servidor con la que previamente tiene almacenada. En realidad lo que compara es el fingerprint o huella dactilar de la clave pública, una sucesión de pares de números hexadecimales que se obtiene a partir de dicha: si coinciden, el cliente se fiará de que el servidor es quien dice ser; si no coinciden, entonces sospechará que hay una suplantación y, o bien avisará (caso de putty), o bien, se negará en rotundo a conectar hasta que no se elimine del cliente la clave pública antigua (caso del cliente de openssh).

Del párrafo anterior, hay dos ideas que es necesario remarcar y que se desglosarán bajo los siguientes epígrafes:

  1. El servidor tiene una pareja de claves pública/privada que le sirven para identificarse ante el cliente (también sirven para cifrar la clave simétrica, pero esto importa poco a los efectos de esta discusión).

  2. El cliente almacena las claves públicas de los servidores para comprobar las identidades de éstos cuando intenta una conexión.

4.5.4.1.1. Claves en el servidor

Se ha afirmado que el servidor tiene una pareja de claves. Esto no es del todo cierto, en realidad, las versiones modernas del servidor openssh tiene varias parejas de claves, cada una de cuales usa un algoritmo diferente de cifrado1. Estas claves está almacenadas en el directorio /etc/ssh:

$ ls -1 /etc/ssh/ssh_host_*
/etc/ssh/ssh_host_ecdsa_key
/etc/ssh/ssh_host_ecdsa_key.pub
/etc/ssh/ssh_host_ed25519_key
/etc/ssh/ssh_host_ed25519_key.pub
/etc/ssh/ssh_host_rsa_key
/etc/ssh/ssh_host_rsa_key.pub

Los ficheros de extensión .pub son los que almacenan las claves públicas. Paralelamente, en el fichero de configuración debe indicarse que estas serán las claves de identificación2:

$ grep -w HostKey /etc/ssh/sshd_config
#HostKey /etc/ssh/ssh_host_rsa_key
#HostKey /etc/ssh/ssh_host_ecdsa_key
#HostKey /etc/ssh/ssh_host_ed25519_key

Cuál de estas parejas se use para la validación depende del cliente: él le indicará al servidor por orden que algoritmos prefiere y el servidor usará el primero que tenga disponible. Se ha dicho también que en realidad lo que se compara es el fingerkey obtenido a partir de la clave pública. De hecho, la primera vez que se conecta el cliente al servidor, se encontrará con esto:

pepe@cliente$ ssh usuario@servidor
The authenticity of host 'servidor (192.168.1.11)' can't be established.
ECDSA key fingerprint is SHA256:vOef4Mo/0obxdDeS9iNIZ5+kQpMB+krMf9XTedRMUbE.
Are you sure you want to continue connecting (yes/no)

Aceptarlo implicará almacenar en el cliente tal fingerprint. Tal huella digital es posible obtenerla manualmente gracias a ssh-keygen:

$ ssh-keygen -l -f /etc/ssh/ssh_host_ecdsa_key.pub
256 SHA256:vOef4Mo/0obxdDeS9iNIZ5+kQpMB+krMf9XTedRMUbE root@servidor (ECDSA)

que obviamente coincide con el fingerprint que observó pepe desde el cliente. El primer número (256) indica la longitud de la clave.

Advertencia

Las claves identifican al servidor, así que es mejor no cambiarlas a menos que las sospechemos comprometidas. Si es absolutamente necesario, pueden redefinirse así:

# ssh-keygen -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key -N ""

que crea una clave ECDSA en el fichero apropiado sin contraseña (esto último necesario, porque el servidor debe ser capaz de usarlas sin pedir la contraseña a nadie). La orden debería repetirse para todos los algoritmos, así que podríamos hacer:

# for algo in rsa ecdsa ed25519; do ssh-keygen -t $algo -f /etc/ssh/ssh_host_${algo}_key -N ""; done

4.5.4.1.2. Claves en el cliente

Como se ha adelantado, los clientes almacenan los fingerprints de las claves públicas de los servidores a los que se han conectado previamente dentro del fichero ~/.ssh/known_hosts. Ahora bien:

pepe@cliente$ ssh-keygen -l -f ~/.ssh/known_hosts
256 SHA256:vOef4Mo/0obxdDeS9iNIZ5+kQpMB+krMf9XTedRMUbE |1|4WnmUKMOBGnrOtOHytjLzB8cKFE=|q7chrsGIIRUBS2S1GlpzA0vDbjo= (ECDSA)
256 SHA256:vOef4Mo/0obxdDeS9iNIZ5+kQpMB+krMf9XTedRMUbE |1|l4/bYn6a2ImKN27oCuwD3wb9M8o=|b5i6kcIRct1K1U9EBVH4PgfoJJU= (ECDSA)

si comprobamos los fingerprints almacenados no seremos capaces de saber a qué servidor corresponde tal fingerprint. Esto se hace así, por privacidad, esto es, por evitar que otros usuarios sean capaces de conocer a qué servidores nos conectamos3. El comportamiento puede modificarse cambiando el valor de la directiva HashKnownHosts en la configuración del cliente. Por tanto, si añadimos como directiva global a ~/.ssh/config:

HashKnownHosts no

se almacenarán las direcciones en claro:

pepe@cliente$ rm -f ~/.ssh/known_hosts
pepe@cliente$ ssh usuario@servidor

[...]

pepe@cliente$ ssh-keygen -l -f ~/.ssh/known_hosts
256 SHA256:vOef4Mo/0obxdDeS9iNIZ5+kQpMB+krMf9XTedRMUbE servidor,192.168.1.11 (ECDSA)

A partir de ahora, cada ve que se conecte a servidor, se confirmará que el firgenprint de la clave proporcionada por este coincide con la almacena. Si no es así, ocurrirá esto:

pepe@cliente$ ssh usuario@servidor
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ECDSA key sent by the remote host is
SHA256:IWvZBm4stPCufdUlUdUtKGkk7P/nNhDsf1R5XDUANtM.
Please contact your system administrator.
Add correct host key in /home/josem/.ssh/known_hosts to get rid of this message.
Offending ECDSA key in /home/josem/.ssh/known_hosts:1
  remove with:
  ssh-keygen -f "/home/josem/.ssh/known_hosts" -R "servidor"
ECDSA host key for servidor has changed and you have requested strict checking.
Host key verification failed.

Que no coincidan las claves puede suponer una suplantación de identidad… o que las claves cambiaron en el servidor por alguna razón. Si la razón es esta segunda, la solución está incluida en el mensaje de advertenca, y es borrar el fingerprint asociado al servidor:

pepe@cliente$ ssh-keygen -R servidor
# Host servidor found: line 1
/home/josem/.ssh/known_hosts updated.
Original contents retained as /home/josem/.ssh/known_hosts.old

Nota

Putty también almacena el fingerprint del servidor, pero a diferencia de éste, no rechaza la conexión cuando detecta un cambio en la clave, sino que advierte del peligro de seguridad y permite aceptar (o no) la nueva clave.

4.5.4.2. Identificación del cliente

Obviamente, nos referimos a su identificación mediante certificado y no mediante contraseña. Por supuesto, la identificación exige primero la creación de las claves y que el servidor acepte este tipo de identificación:

$ grep -w PubkeyAuthentication /etc/ssh/sshd_config
#PubkeyAuthentication yes

4.5.4.2.1. Cliente openssh

En este caso, laa generación es sencilla. La orden:

$ ssh-keygen -t ecdsa -C "Comentario alusivo a la clave"

generará una clave de tipo ECDSA y, como fichero, se escogerá el predeterminado para este tipo de clave (~/.ssh/id_ecdsa y ~/.ssh/id_ecdsa.pub, para la clave pública). Si no se altera la configuración, en el momento en que intentemos conectar a cualquier servidor se intentará usar esta clave para la autenticación. Tras generar la pareja de claves se nos pide una clave de paso, que no es más que una contraseña necesaria para poder usar la clave privada. Fijarla obliga a escribir tal contraseña antes de usarla y nos asegura ante un hurto de las claves.

Es obvio, que no basta con generar la clave en el cliente: en el servidor debe alojarse la clave pública para que, cuando se produzca la comunicación, pueda asegurarse que quien se conecta desde el cliente es el propietario de la clave privada correspondiente. Para ello, puede hacerse:

$ ssh-copy-id usuario@servidor

que subirá la clave4 al fichero del servidor que almacena las claves públicas (~./ssh/authorized_keys)5. A partir de ahora, al intentar ingresar en el servidor, se usará en primer término la identificación mediante el certificado y se nos pedirá la clave de paso (ya que hay que usar la clave privada) o nada, si no se introdujo contraseña al generar las claves.

Nota

No obstante, lo anterior, es posible usar claves almacenadas en otros ficheros. Por ejemplo:

$ ssh-keygen -t edcsa -f .ssh/id_servidor -C "Clave para 'servidor'"
$ ssh-copy-id -i .ssh/id_servidor usuario@servidor
$ ssh -i .ssh/id_servidor usuario@servidor

e incluso indicar cuál es el nombre de la clave en la configuración:

Host svm
   Hostname       servidor
   User           usuario
   IdentityFile   ~/.ssh/id_%h

de manera que cuando conectemos a servidor siempre usemos ~/.ssh/id_servidor6.

4.5.4.2.2. Cliente putty

Debemos efectuar las mismas acciones que en el caso anterior. El equivalente a ssh-keygen en la suite de putty es puttygen:

Captura de puttygen

Por hacer

HACER la captura…

Al generar el par de claves (Generate) el programa quedará esperando que movamos aletariamente el ratón por encima de la superficie vacía a fin de lograr mayor aletoriedad. Al acabar la generación, se podrá escribir un comentario y la clave de paso o contraseña de la propia clave. Podemos entonces guardar la clave privada (Save private key), pero la clave pública no es de poca ayuda, puesto que no tiene el mismo formato que las claves que genera openssh. Sin embargo, la clave pública, tal y como la exige openssh, se muestra en la propia pantalla con lo que se puede copiar y pegar en un fichero.

Dado que ahora no disponemos de ssh-id-copy, hay que subir manualmente la clave pública al servidor para incluirla en en ~/.ssh/authorized_keys. Quizás lo más sencillo es abrir una sesión de putty y copiar contenido de la clave pública directamente sobre el fichero anterior, en vez de en un fichero cualquiera del cliente windows.

Notas al pie

1

Hasta la versión 7.0, también existía una versión DSA, pero acabó por deshabilitarse su uso al considerarla débil (véase la información relativa par más información).

2

Las líneas aparecen comentadas, pero recordemos que en este fichero las directivas comentadas muestran el valor predeterminado.

3

Este comportamiento se deriva de la configuración predeterminada de las últimas versiones de debian:

$ grep -w HashKnownHosts /etc/ssh/ssh_config
    HashKnownHosts yes
4

No especificamos dónde está la clave (opción -i), pero carece de relevancia puesto que estamos usando los nombres predeterminados.

5

Tal es así, que podríamos haber hecho la subida de forma artesanal:

$ ssh usuario@servidor "mkdir -p ~/.ssh; cat >> ~/.ssh/authorized_keys" < ~/.ssh/id_ecdsa.pub
6

Consúltese el apartado TOKENS de la página de manual de ssh_config para entender por qué %h se convierte en el nombre de la máquina remota (servidor).