acerca de HTML

Referencia de etiquetas

Etiqueta keygen en HTML: obsoleta y generación de claves

La etiqueta <keygen> está obsoleta y no debe usarse en HTML nuevo. Generaba un par de claves y participaba en el envío de una solicitud de certificación desde un formulario. No existe una etiqueta que la reemplace directamente: hoy se elige Web Crypto para operaciones con claves, un proceso de enrolamiento para certificados o WebAuthn si el objetivo es autenticar usuarios. Esta guía documenta su uso histórico y una migración educativa.

Ejemplo histórico: solicitar un certificado

Este código sirve para reconocer un formulario antiguo; no lo ejecutes como una demostración actual:

<form action="/solicitar-certificado" method="post">
  <keygen name="clave" keytype="RSA">
  <button type="submit">Solicitar certificado</button>
</form>

Según HTML5 de 2014, <keygen> era un control asociado a formularios, admitido donde se esperaba contenido de frase. Era vacío: no contenía texto ni llevaba </keygen>. Aquí su propietario era <form>.

Al enviar, guardaba la clave privada en el almacén local y enviaba al servidor la pública empaquetada con una firma, en formato SPKAC. El navegador podía ofrecer ajustes del generador; no había una apariencia uniforme. /solicitar-certificado es un destino ilustrativo, no una ruta de este sitio.

Claves, solicitud, certificado y autenticación

Imagina un portal que exigía un certificado de cliente. Generar las claves era el primer paso; preparar la solicitud permitía pedir el certificado. Una autoridad debía emitirlo y el usuario instalarlo antes de emplearlo para autenticarse. El formulario no resolvía todo ese proceso.

<keygen> no era un campo de contraseña. Cambiarlo por <input type="password"> recogería otro dato y dejaría sin implementar el flujo criptográfico. Retirarlo también exige revisar qué espera el servidor: un formulario que aún puede enviarse no demuestra que haya una solicitud válida.

Atributos antiguos y decisiones de migración

La versión histórica consultada definía estos atributos:

  • name: nombre del dato enviado; no nombraba una contraseña.
  • challenge: cadena incluida con la clave pública firmada; si faltaba, se utilizaba una cadena vacía.
  • keytype: tipo de clave. Definía rsa; omitirlo elegía RSA si estaba soportado. Un valor desconocido producía un valor vacío; el estándar no exigía soportar algoritmos.
  • disabled: booleano que impedía interacción y envío. Su presencia, incluso como disabled="false", deshabilitaba el control.

También admitía form y autofocus, además de atributos globales como id y class. Los globales no generaban claves; CSS solo cambiaba la presentación.

Al migrar, los parámetros pasan a la API o al protocolo elegido. keytype="RSA" no se copia como algoritmo de Web Crypto: hay que elegir la operación concreta. Tampoco traslades challenge a WebAuthn; su desafío forma parte de un protocolo propio y debe seguir sus reglas. crypto.subtle.generateKey() es un método JavaScript, no un atributo HTML.

Qué alternativa corresponde a cada objetivo

  • Operaciones criptográficas locales: Web Crypto permite generar y utilizar claves. La aplicación decide algoritmo, usos y custodia.
  • Certificados: diseña solicitud, validación, emisión, instalación, renovación y revocación con el servidor y la autoridad correspondiente. Para equipos administrados, el Living Standard recomienda las capacidades nativas de gestión del dispositivo.
  • Inicio de sesión con credenciales de clave pública: WebAuthn puede corresponder a ese objetivo. Exige registro y verificación por el servidor; no reproduce el envío SPKAC ni emite certificados de cliente.

Ejemplo actual: generar un par local con Web Crypto

Guarda este documento completo como claves-locales.html. No necesita CSS, archivos adicionales ni un endpoint: solo genera claves en memoria y muestra sus tipos.

<!doctype html>
<html lang="es">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Generación local de claves</title>
</head>
<body>
  <h1>Generación local de claves</h1>
  <p>Prueba educativa: no solicita certificados ni inicia sesión.</p>
  <button id="generar" type="button" disabled>Generar par de claves</button>
  <p id="estado" role="status">Este ejemplo necesita JavaScript.</p>
  <noscript><p>Sin JavaScript no se generan claves.</p></noscript>

  <script>
    const boton = document.getElementById("generar");
    const estado = document.getElementById("estado");
    let generando = false;

    if (!window.isSecureContext || !window.crypto?.subtle?.generateKey) {
      estado.textContent = "Se necesita un contexto seguro y Web Crypto.";
    } else {
      boton.disabled = false;
      estado.textContent = "Pulsa el botón para generar un par local.";

      boton.addEventListener("click", async () => {
        if (generando) return;
        generando = true;
        estado.textContent = "Generando...";
        try {
          const par = await window.crypto.subtle.generateKey(
            { name: "ECDSA", namedCurve: "P-256" },
            false,
            ["sign", "verify"]
          );
          estado.textContent = "Par generado: " +
            par.publicKey.type + " / " + par.privateKey.type +
            ". No se han enviado ni guardado claves.";
        } catch {
          estado.textContent = "No se pudo generar el par de claves.";
        } finally {
          generando = false;
        }
      });
    }
  </script>
</body>
</html>

Para probarlo, sirve la carpeta desde un servidor estático local existente y abre http://localhost:PUERTO/claves-locales.html, usando su puerto real, o publícalo mediante HTTPS. localhost se considera un origen potencialmente fiable según Secure Contexts. No dependas de abrir un archivo con file: ni de un origen HTTP remoto.

Llega al botón con Tab y actívalo con Enter o Espacio. El resultado esperado es «Par generado: public / private. No se han enviado ni guardado claves.» El mensaje usa una región de estado; el foco permanece en el botón y no depende de un color. Sin JavaScript se conservan las instrucciones y el botón deshabilitado. Sin la API o el contexto adecuado aparece el aviso, y un fallo de generación muestra un error.

La operación devuelve una promesa que resuelve a un CryptoKeyPair con publicKey y privateKey. Web Crypto documenta ECDSA, P-256 y los usos sign y verify. El argumento false impide exportar la clave privada; la pública sigue siendo exportable. El ejemplo muestra solo metadatos: no imprime claves, no llama a exportKey() ni persiste el par. Al recargar no puedes recuperar ese par desde la demo.

Preguntas y límites al migrar

¿Qué etiqueta reemplaza a keygen?

Ninguna. Conserva el HTML que necesites para la interfaz y redefine la función con la API o el proceso apropiado. Un botón que llama a Web Crypto no equivale al antiguo control de formulario.

¿Generar claves emite un certificado?

No. Esta demo tampoco autentica usuarios. Una migración real debe definir el formato de solicitud, el flujo de servidor y la custodia de las claves, incluida su recuperación o sustitución. Hacer una clave no exportable limita su exportación; no protege por sí solo una aplicación comprometida ni garantiza almacenamiento en hardware.

Consulta la guía de <form> para el envío y la guía de <input> para controles de entrada. La guía de <script> explica cómo ejecutar el código de esta demo; el elemento no sustituye por sí mismo a <keygen>.

Compatibilidad y fuentes

Revisión del 3 de octubre de 2026. El HTML Living Standard clasifica <keygen> como obsoleto y no conforme; un documento heredado no garantiza generación ni envío hoy. Su sintaxis se describe únicamente con la referencia histórica de 2014.

MDN documenta los parámetros, el resultado y la compatibilidad de generateKey(). La disponibilidad de Web Crypto depende de contexto seguro, navegador y algoritmo: comprueba la API y gestiona rechazos, como hace el ejemplo. La prueba de esta guía se realizó en Chromium 153; no constituye una garantía para todos los entornos.