por - Autenticación de clave pública SSH con Libssh2 C++
ssh-keygen-t rsa (1)
He encontrado la solución. Lo que hice en la actualización 1 fue la solución real, pero mi clave de servidor se modificó por alguna razón, no estoy seguro de por qué, por lo que cuando dijo que no podía vincular el nombre de usuario con la clave, era correcto.
La solución completa es la siguiente:
No uses el libssh2 de NuGet, es muy antiguo. Descargué la última fuente de GitHub en https://github.com/libssh2/libssh2/releases y luego completé los siguientes pasos para crear libssh2 en Visual Studio.
- Empuje todos los archivos .c en libssh2 / src en un proyecto vacío de Win32 C ++ (DLL o biblioteca estática), excepto libgcrypt.c / openssl.c, de los cuales solo elija el adecuado para su biblioteca criptográfica.
- Agregue su directorio de inclusión OpenSSL o libgcrypt a la ruta de inclusión del proyecto
- Añadir libssh2 / include a la ruta de inclusión del proyecto
- Agregue libssh2 / win32 a la ruta de inclusión del proyecto
- Agregue las bibliotecas criptográficas adecuadas a la lista de bibliotecas adicionales del proyecto
- Construir
- Trabajo hecho
Los pasos anteriores se tomaron de https://www.libssh2.org/mail/libssh2-devel-archive-2012-09/0029.shtml
El libssh2 se vinculó a openssl durante la compilación.
Vincula tu proyecto a la última compilación que acabas de hacer para libssh2 y usa el método
libssh2_userauth_publickey_frommemory(LIBSSH2_SESSION *session, const char *username, size_t username_len, const char *publickeyfiledata, size_t publickeyfiledata_len, const char *privatekeyfiledata, size_t privatekeyfiledata_len, const char *passphrase);
Y eso es.
Estoy trabajando en un proyecto en el que estoy realizando el reenvío de puertos a MySQL usando libssh2 en C ++. Lo tengo funcionando para la autenticación de nombre de usuario / contraseña, pero ahora quiero hacerlo usando la autenticación de clave pública / privada. La documentación de libssh2 es bastante deficiente, por lo que me resulta difícil averiguar qué debo hacer.
Lo que estoy tratando de hacer es tener una aplicación de Android que publique datos en mi aplicación C ++, donde a C ++ se le darán los detalles de SSH junto con la clave de autenticación y se creará el túnel SSH. C ++ está recibiendo la multa de la clave y luego estoy haciendo lo siguiente para realizar la autenticación de la clave pública.
else if (this->getAuthMethod() == SupportedAuthMethods::AUTH_PUBLICKEY)
{
string test = this->getSSHPrivateKey();
boost::replace_all(test, "/n", "");
unsigned char * key = (unsigned char *)test.c_str();
size_t sizeofkey = strlen((char*)key);
cout << key << endl;
stringstream logstream;
logstream << "Using public key authentication for SSH Host: " << this->getSSHHostnameOrIPAddress();
this->bitsLibrary->writeToLog(logstream.str(), "SSHTunnelForwarder", "authenticateSSHServer");
if (chosenAuthMethod & SupportedAuthMethods::AUTH_PUBLICKEY)
{
//int result = 0;
int result = libssh2_userauth_publickey(this->session, this->getUsername().c_str(), key, sizeofkey, SSHTunnelForwarder::publicKeyAuthComplete, 0);
if (result != 0)
{
char * error = NULL;
int len = 0;
int errbuf = 0;
libssh2_session_last_error(this->session, &error, &len, errbuf);
this->bitsLibrary->writeToLog(std::string(error), "SSHTunnelForwarder", "auth");
JSONResponseGenerator jsonResponse;
jsonResponse.generateJSONResponse(API_AUTH_FAILURE, "InvalidPublicKey");
return jsonResponse.getJSONString();
}
}
}
Leí en alguna parte que no debería tener nuevas líneas, es por eso que estoy reemplazando el / n por caracteres en blanco, pero con o sin esto no hace una diferencia.
La documentación muy básica menciona que uno de los argumentos para libssh2_userauth_publickey
es una devolución de llamada de la siguiente manera:
int name(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, const unsigned char *data, size_t data_len, void **abstract);
pero no puedo encontrar ninguna información en ningún lugar sobre qué es esta devolución de llamada o qué debería contener. En mi llamada de función a libssh2_userauth_publickey paso SSHTunnelForwarder::publicKeyAuthComplete
y actualmente esta función solo tiene lo siguiente:
int SSHTunnelForwarder::publicKeyAuthComplete(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len,
const unsigned char *data, size_t data_len, void **abstract)
{
cout << "In SSH Auth Callback" << endl;
return 0;
}
Este método de arriba no se llama, aunque espero que ni siquiera sea correcto.
Cuando ejecuto mi código sobre el resultado de libssh2_userauth_publickey es 19 y el error que se devuelve del método get_last_message()
es invalid public key
. Sé que el archivo de clave pública está bien ya que puedo usarlo en una aplicación SSH en Android y puedo autenticarme exitosamente con mi servidor.
ACTUALIZACIÓN 1
Me las arreglé para hacer algunos progresos, encontré que hay una función llamada:
libssh2_userauth_publickey_frommemory(LIBSSH2_SESSION *session, const char *username, size_t username_len, const char *publickeyfiledata, size_t publickeyfiledata_len, const char *privatekeyfiledata, size_t privatekeyfiledata_len, const char *passphrase);
La versión libssh2 que tenía era del administrador de paquetes de NuGet y descubrió que la última versión es bastante antigua, así que construí la última versión 1.7.0 de GitHub dentro de Visual Studio y volví a vincular mi proyecto a esta nueva versión.
Ahora he reemplazado la función de autenticación pública original que estaba usando con esta versión, por lo que ahora mi código se ve así:
int result = libssh2_userauth_publickey_frommemory(this->session, username.c_str(), username.length(), nullptr, 0, test.c_str(), sizeofkey, nullptr);
Esta función me confunde un poco que quiere la clave pública y la clave privada, ya que todo lo que sé sobre SSH (es cierto que no es una gran cantidad) la clave pública permanece en el servidor, y el usuario que desea iniciar sesión solo tiene acceso a la clave privada. llave.
Descubrí que alguien más estaba preguntando esto y se hizo un parche para permitir un puntero nulo para la clave pública, así que pasé nullptr para la clave pública y 0 para la longitud de la clave pública. También he puesto un nullptr para la frase de contraseña del certificado ya que no se ha establecido.
Cuando ejecuto este código ahora obtengo el error -18 que es invalid username/public key combination
. Sin embargo, una vez más, sé que el nombre de usuario y el archivo de clave privada que estoy usando son correctos, ya que puedo usarlo en una aplicación cliente SSH en Android para conectarme a mi servidor SSH.