我正在一个项目中进行端口转发,使用C++中的libssh2实现MySQL。我已经通过用户名/密码身份验证使其正常工作,但现在想改用公钥/私钥身份验证。Libssh2的文档相当不好,所以我很难找出我需要做什么。
我的目标是让Android应用程序将数据发布到我的C++应用程序,其中C++将获取SSH详细信息以及认证密钥,并创建SSH隧道。 C++成功获取密钥,然后我执行以下操作进行公钥身份验证。
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();
}
}
}
我在某个地方读到,它不应该有新行,这就是为什么我将 \n 替换为空格字符,但是有或没有这个并没有影响。
非常基础的文档提到,libssh2_userauth_publickey
的参数之一是一个回调函数,如下所示:
int name(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, const unsigned char *data, size_t data_len, void **abstract);
但是我无法在任何地方找到关于这个回调函数是什么或者它应该包含什么信息的任何信息。在我的函数调用中,我传递了 SSHTunnelForwarder::publicKeyAuthComplete
,当前该函数只包含以下内容:
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;
}
尽管我期望这个方法被调用,但实际上并没有被调用,虽然这样可能离正确还有很远的距离。
当我运行上述代码时,libssh2_userauth_publickey的结果为19,而从get_last_message()
方法返回的错误是invalid public key
。 我知道公钥文件没问题,因为我可以在Android上的SSH应用程序中使用它,并且可以成功地验证我的服务器。
更新1
我已经取得了一些进展,我发现有一个名为:
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);
我使用NuGet软件包管理器获取的libssh2版本非常陈旧,因此我从GitHub中最新的1.7.0版本中在Visual Studio中进行了构建,并将我的项目重新链接到了这个新版本。
现在,我已经用这个新版本替换了我之前使用的原始publickey auth函数,因此我的代码看起来像这样:
int result = libssh2_userauth_publickey_frommemory(this->session, username.c_str(), username.length(), nullptr, 0, test.c_str(), sizeofkey, nullptr);
这个函数让我有点困惑,因为它需要公钥和私钥。就我所知关于SSH的一切(尽管不是太多),公钥留在服务器上,希望登录的用户只能访问私钥。
我发现别人也在问这个问题,并修复了一个允许使用null指针作为公钥的补丁,因此我已经将nullptr传递给公钥,0传递给公钥长度。同时我也将证书密码设为nullptr,因为它还没有被设置。
现在当我运行这段代码时,出现了错误-18,这是“用户名/公钥组合无效”的意思。然而,我知道我正在使用的用户名和私钥文件是正确的,因为我可以在Android上的SSH客户端应用程序中使用它连接到我的SSH服务器。