Pular para o conteúdo
ecdsa.com
Linha de comando

OpenSSH (ssh-keygen)

O OpenSSH 10, o conjunto de ferramentas SSH cujo ssh-keygen também converte chaves e assina arquivos e commits do git: Ed25519 por padrão, troca de chaves híbrida com ML-KEM em primeiro lugar, DSA removido — e assinaturas ECDSA na codificação mpint própria do SSH.
Licença
SSH-OpenSSH
Versão verificada
10.3p1 ·
Código-fonte
github.com/openssh/openssh-portable
Documentação
www.openssh.com/manual.html

Visão geral da compatibilidade

ECDSAEdDSAPós-quântica

Curvas ECDSA
P-256P-384P-521
EdDSA
Ed25519
Formatos de chave pública
spki-pemopensshpkcs1
Formatos de chave privada
pkcs8-pemencrypted-pkcs8sec1-pempkcs1openssh

Além de ssh e sshd, o OpenSSH traz o ssh-keygen, que gera e converte chaves e, com -Y sign, produz assinaturas SSHSIG para arquivos e commits do git. Os fatos desta página foram verificados nos pacotes do Alpine 3.24.2, OpenSSH 10.3p1, vinculado ao OpenSSL 3.5.8 da imagem. Sem -t, o ssh-keygen grava uma chave Ed25519. Chaves ECDSA existem apenas para P-256, P-384 e P-521 (-b 224 é recusado), não há Ed448, e o DSA foi removido: ssh-keygen -t dsa responde “unknown key type dsa”. Inspecione qualquer chave com o inspetor de chaves SSH.

Sem arquivo de configuração, o cliente oferece primeiro a troca de chaves híbrida mlkem768x25519-sha256 e depois sntrup761x25519-sha512 — proteção pós-quântica para as chaves de sessão. ssh -Q sig não lista nenhum algoritmo de assinatura pós-quântico, então a autenticação do host e do usuário continua clássica. O RSA com SHA-1 (ssh-rsa) ainda está implementado, mas fica fora das listas padrão de chaves de host e de chaves públicas, então, com as configurações padrão, o cliente nunca o usa; uma contraparte que não ofereça nada mais recente que ssh-rsa exige reativá-lo explicitamente, por exemplo com PubkeyAcceptedAlgorithms +ssh-rsa para chaves de usuário. Confira o que um servidor negocia com a auditoria de servidores SSH.

Uma assinatura ECDSA no SSH não é DER nem r‖s bruto: o blob é a string ecdsa-sha2-nistp256 seguida de uma string que contém r e s como mpints do SSH (RFC 5656). Converter assinaturas de ou para X.509, JWS ou WebAuthn, portanto, significa refazer a codificação dos dois inteiros. Os nonces são aleatórios — duas assinaturas do mesmo arquivo foram diferentes —, o s não é normalizado, e uma assinatura com s substituído por n − s passou na verificação.

As assinaturas SSHSIG (ssh-keygen -Y sign) calculam o hash da mensagem com SHA-512 por padrão; -O hashalg=sha256 é a única alternativa, e SHA-1 e SHA-384 são recusados. O namespace indicado com -n faz parte do que é assinado, e verificar uma assinatura file como email falha com “namespace does not match”. As falhas podem ser distinguidas no stderr — “invalid format” para um blob danificado, “incorrect signature” para uma assinatura válida sobre outros dados —, enquanto o stdout diz “Could not verify signature.” nos dois casos. Confira uma assinatura com o verificador de assinaturas SSH.

ssh-keygen -e -m PKCS8 exporta uma chave pública como SPKI em PEM, e -i -m PKCS8 a importa de volta; -m PEM também gera SPKI para ECDSA, mas PKCS#1 para RSA, e -m RFC4716 gera o formato “SSH2 PUBLIC KEY”. Chaves públicas Ed25519 não podem ser exportadas com -e -m PKCS8 (“unsupported key type ED25519”), embora -p -m PKCS8 regrave uma chave privada Ed25519 como PKCS#8. As chaves privadas são armazenadas como OPENSSH PRIVATE KEY por padrão; -p -m PEM regrava chaves ECDSA como SEC1 e chaves RSA como PKCS#1, e -m PKCS8 com frase secreta grava PKCS#8 criptografado.

Os fatos e as verificações por trás deles

Nada abaixo foi copiado da documentação. A verificação content/libraries/verify/openssh/run.sh executou OpenSSH (ssh-keygen) 10.3p1 na imagem de contêiner alpine:3.24.2 em 20 de outubro de 2026; a página precisa corresponder ao que a verificação imprimiu, e cada fato lista essas linhas.

  • Tipo de chave padrão

    ed25519

    ssh-keygen sem -t gravou uma chave ssh-ed25519.

    Registrado pela verificação
    fact default-key-type = ed25519
    evidence default-key-type: ssh-keygen without -t wrote a ssh-ed25519 key
  • Curvas ECDSA

    P-256P-384P-521

    -b 256, 384 e 521; -b 224 é recusado com “valid lengths are 256, 384 or 521 bits”.

    Registrado pela verificação
    fact ecdsa-curves = P-256, P-384, P-521
    evidence ecdsa-curves: ssh -Q key: ssh-ed25519 ssh-ed25519-cert-v01@openssh.com sk-ssh-ed25519@openssh.com sk-ssh-ed25519-cert-v01@openssh.com ecdsa-sha2-nistp256 ecdsa-sha2-nistp256-cert-v01@openssh.com ecdsa-sha2-nistp384 ecdsa-sha2-nistp384-cert-v01@openssh.com ecdsa-sha2-nistp521 ecdsa-sha2-nistp521-cert-v01@openssh.com sk-ecdsa-sha2-nistp256@openssh.com sk-ecdsa-sha2-nistp256-cert-v01@openssh.com ssh-rsa ssh-rsa-cert-v01@openssh.com
  • EdDSA

    Ed25519

    ssh-ed25519 e sua variante FIDO aparecem em ssh -Q key; não há tipo de chave Ed448.

    Registrado pela verificação
    fact eddsa = Ed25519
  • Chaves DSA

    removed

    ssh-keygen -t dsa falha com “unknown key type dsa”, e ssh-dss não aparece em ssh -Q key.

    Registrado pela verificação
    fact dsa-keys = removed
  • Troca de chaves padrão

    mlkem768x25519-sha256

    Primeira entrada de kexalgorithms em ssh -F none -G.

    Registrado pela verificação
    fact default-kex = mlkem768x25519-sha256
    evidence default-kex: ssh -F none -G: kexalgorithms mlkem768x25519-sha256,sntrup761x25519-sha512,sntrup761x25519-sha512@openssh.com,curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256
  • Algoritmos pós-quânticos

    ML-KEMsntrup761

    Trocas de chaves híbridas mlkem768x25519-sha256 e sntrup761x25519-sha512; nenhum algoritmo de assinatura pós-quântico em ssh -Q sig.

    Registrado pela verificação
    fact pqc = ML-KEM, sntrup761
    evidence pqc: ssh -Q kex: diffie-hellman-group1-sha1 diffie-hellman-group14-sha1 diffie-hellman-group14-sha256 diffie-hellman-group16-sha512 diffie-hellman-group18-sha512 diffie-hellman-group-exchange-sha1 diffie-hellman-group-exchange-sha256 ecdh-sha2-nistp256 ecdh-sha2-nistp384 ecdh-sha2-nistp521 curve25519-sha256 curve25519-sha256@libssh.org sntrup761x25519-sha512 sntrup761x25519-sha512@openssh.com mlkem768x25519-sha256
    evidence pqc: ssh -Q sig: ssh-ed25519 sk-ssh-ed25519@openssh.com ecdsa-sha2-nistp256 ecdsa-sha2-nistp384 ecdsa-sha2-nistp521 sk-ecdsa-sha2-nistp256@openssh.com webauthn-sk-ecdsa-sha2-nistp256@openssh.com ssh-rsa rsa-sha2-256 rsa-sha2-512
  • Assinaturas ssh-rsa com SHA-1

    disabled-by-default

    ssh-rsa aparece em ssh -Q sig, mas não nos valores padrão de pubkeyacceptedalgorithms nem de hostkeyalgorithms.

    Registrado pela verificação
    fact ssh-rsa-sha1 = disabled-by-default
    evidence ssh-rsa-sha1: ssh-rsa in ssh -Q sig: yes; in the default pubkeyacceptedalgorithms or hostkeyalgorithms: no
    evidence ssh-rsa-sha1: with -o PubkeyAcceptedAlgorithms=+ssh-rsa it is in the list: yes
  • Codificação da assinatura ECDSA

    ssh-mpint

    O blob da assinatura SSHSIG contém a string do tipo e r e s como mpints mínimos do SSH.

    Registrado pela verificação
    fact ecdsa-signature-encoding = ssh-mpint
    evidence ecdsa-signature-encoding: ssh-keygen -Y sign: hash=sha512 type=ecdsa-sha2-nistp256 mpints=yes
  • Nonce do ECDSA

    random

    Duas assinaturas do mesmo arquivo foram diferentes.

    Registrado pela verificação
    fact ecdsa-nonce = random
    evidence ecdsa-nonce: two signatures of one file are different
  • Low-S ao assinar

    either

    O s não é normalizado: valores high-S apareceram entre 32 assinaturas.

    Registrado pela verificação
    fact ecdsa-low-s-sign = either
    evidence ecdsa-low-s-sign: signatures with s > n/2 among 32: yes
  • High-S ao verificar

    accepts-high-s

    Uma assinatura com s substituído por n − s foi verificada como “Good”.

    Registrado pela verificação
    fact ecdsa-low-s-verify = accepts-high-s
    evidence ecdsa-low-s-verify: s replaced by n - s: ok
  • Saída da verificação em caso de falha

    distinguishable

    O stderr diz “invalid format” para r‖s bruto e para 3 bytes, e “incorrect signature” para uma mensagem errada; o código de saída é 255 nos dois casos.

    Registrado pela verificação
    fact cli-verify-output = distinguishable
  • Hash padrão do SSHSIG

    sha512

    O cabeçalho SSHSIG de uma assinatura padrão indica sha512.

    Registrado pela verificação
    fact sshsig-default-hash = sha512
    evidence sshsig-default-hash: hash=sha512 type=ecdsa-sha2-nistp256 mpints=yes
  • Algoritmos de hash do SSHSIG

    sha256sha512

    -O hashalg= aceitou sha256 e sha512 e recusou sha1 e sha384.

    Registrado pela verificação
    fact sshsig-hash-algorithms = sha256, sha512
    evidence sshsig-hash-algorithms: ssh-keygen -Y sign -O hashalg= accepted: sha256, sha512
  • Espaço de nomes do SSHSIG

    enforced

    Uma assinatura feita com -n file falhou com -n email: “namespace does not match”.

    Registrado pela verificação
    fact sshsig-namespace = enforced
  • Formatos de chave pública

    spki-pemopensshpkcs1

    SPKI em PEM (-e -m PKCS8, importado de volta com -i), a linha do OpenSSH e PKCS#1 para RSA (-e -m PEM).

    Registrado pela verificação
    fact public-key-formats = spki-pem, openssh, pkcs1
    evidence public-key-formats: P-256 -e -m PKCS8: -----BEGIN PUBLIC KEY-----, -i back to the same key: yes
    evidence public-key-formats: P-256 -e -m PEM: -----BEGIN PUBLIC KEY-----; -e -m RFC4716: ---- BEGIN SSH2 PUBLIC KEY ----
    evidence public-key-formats: RSA -e -m PEM: -----BEGIN RSA PUBLIC KEY-----, -i back to the same key: yes
  • Formatos de chave privada

    pkcs8-pemencrypted-pkcs8sec1-pempkcs1openssh

    PKCS#8, PKCS#8 criptografado e SEC1 para ECDSA e PKCS#1 para RSA, cada um lido de volta por ssh-keygen -y, além do formato padrão do OpenSSH.

    Registrado pela verificação
    fact private-key-formats = pkcs8-pem, encrypted-pkcs8, sec1-pem, pkcs1, openssh
    evidence private-key-formats: P-256 default: -----BEGIN OPENSSH PRIVATE KEY-----; -m PKCS8: -----BEGIN PRIVATE KEY----- (read back: yes); -m PKCS8 with a passphrase: -----BEGIN ENCRYPTED PRIVATE KEY----- (read back: yes); -m PEM: -----BEGIN EC PRIVATE KEY----- (read back: yes)
    evidence private-key-formats: RSA -m PEM: -----BEGIN RSA PRIVATE KEY----- (read back: yes); Ed25519 -m PKCS8: -----BEGIN PRIVATE KEY----- (read back: yes); Ed25519 -m PEM: refused

Uso

Gere uma chave Ed25519, assine um arquivo no namespace `file` e verifique-o com um arquivo allowed_signers.
# Without -t, ssh-keygen generates an Ed25519 key.
ssh-keygen -q -N "" -C alice@example.com -f id_ed25519
printf 'order #1042 approved\n' > order.txt

# -n names what the signature is for; a different namespace fails verification.
ssh-keygen -q -Y sign -f id_ed25519 -n file order.txt   # writes order.txt.sig

# Verifiers trust keys through allowed_signers: a principal, then the public key.
echo "alice@example.com $(cut -d' ' -f1,2 id_ed25519.pub)" > allowed_signers
ssh-keygen -Y verify -f allowed_signers -I alice@example.com -n file -s order.txt.sig < order.txt

O executor de trechos de código roda cada exemplo literalmente na imagem de contêiner alpine:3.24.2, e a execução falha se a saída não corresponder.

Configuração
apk add --no-cache -q openssh-keygen=10.3_p1-r1 >/dev/null
Comando
sh sign.sh
A saída deve corresponder a (expressão regular)
Good "file" signature for alice@example\.com with ED25519 key SHA256:

Bibliotecas