TL; DR
Os comentários mais úteis do @forcefsck. Infelizmente ele não preencheu a resposta, então eu não pude conceder a recompensa. Em suma, a resposta é PEM + RSA1 + novo formato openSSH que é descrito na pergunta e o principal problema era com o PEM.
O longo & Bônus
O OpenSSH está usando o analisador do openSSL ( PEM_read_bio_PrivateKey()
), que tem o único valor de retorno para todas as falhas ( NULL
) e, se falhar, o openSSH espera que tenha sido por causa da frase secreta incorreta.
Sem OpenSSL
Eu apenas tentei criar o OpenSSH sem o suporte OpenSSL ( --without-openssl
configure option) e o comportamento está "correto":
# ./ssh-add <(echo "")
Error loading key "/dev/fd/63": invalid format
Corrigir com o OpenSSL
A outra coisa é como consertar isso. O puxão vem da função ERR_get_error()
e seus amigos, o que deve nos permitir distinguir entre diferentes erros.
Erros incorretos de frase secreta
# ./ssh-add /tmp/rsa
140480353842840:error:0906A068:lib(9):func(106):reason(104):pem_lib.c:457:
Enter passphrase for /tmp/rsa:
140480353842840:error:06065064:lib(6):func(101):reason(100):evp_enc.c:592:
140480353842840:error:0906A065:lib(9):func(106):reason(101):pem_lib.c:482:
Razões: PEM_R_BAD_PASSWORD_READ
, PEM_R_BAD_BASE64_DECODE
, PEM_R_BAD_DECRYPT
.
Analisar códigos de erro
# ./ssh-add <(echo "")
139656018548376:error:0906D06C:lib(9):func(109):reason(108):pem_lib.c:701:Expecting: ANY PRIVATE KEY
ou isto:
140654301202072:error:0906D066:lib(9):func(109):reason(102):pem_lib.c:809:
Razão: PEM_R_NO_START_LINE
, PEM_R_BAD_END_LINE
, mas pode haver mais possibilidades.
Solução?
Adicionar mais verificações para erros do OpenSSL deve nos dar uma opção para escolher qual erro queremos marcar como erro de "formato" e qual é a "senha incorreta". Isso está localizado na função sshkey_parse_private_pem_fileblob()
em sshkey.c
na linha em torno de 3800.
unsigned long e = ERR_get_error();
if (ERR_GET_REASON(e) == PEM_R_NO_START_LINE ||
ERR_GET_REASON(e) == PEM_R_BAD_END_LINE) {
r = SSH_ERR_INVALID_FORMAT;
} else {
r = SSH_ERR_KEY_WRONG_PASSPHRASE;
}