mirror of
https://git.ffmpeg.org/ffmpeg.git
synced 2026-10-28 10:04:37 +08:00
avformat/libssh: verify the SSH server host key
The sftp protocol connected and authenticated without checking the server host key, so credentials were sent to any or spoofed server. Verify against known_hosts (ssh_session_is_known_server, with a pre-0.8 fallback) before authenticating; add a 'verify' option (default on) to opt out. Strict checking is forced on for the check: libssh otherwise reports an unknown server, and since 0.8 even a changed key, as known when the parsed ssh config says StrictHostKeyChecking no. This changes the default behaviour: like OpenSSH with StrictHostKeyChecking=yes, sftp:// now refuses servers that are not in the known_hosts file or whose key differs from the recorded one. Fixes: credentials sent to unverified SSH servers (CWE-295) Fixes: ZmW0mOvhU0qN Found-by: Joshua Rogers <joshua.rogers@aisle.com> Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
This commit is contained in:
1 parent
57a2e704b4
commit
2b822b7fb6
2 files changed
+49
No files matched your search
@@ -1239,6 +1239,11 @@ truncating. Default value is 1.
|
||||
Specify the path of the file containing private key to use during authorization.
|
||||
By default libssh searches for keys in the @file{~/.ssh/} directory.
|
||||
|
||||
@item verify
|
||||
Verify the server host key against the known_hosts file before
|
||||
authenticating, if set to 1. Servers that are not in the file, or whose
|
||||
key differs from the one recorded there, are refused. Default value is 1.
|
||||
|
||||
@end table
|
||||
|
||||
Example: Play a file stored on remote server.
|
||||
|
||||
@@ -40,8 +40,45 @@ typedef struct {
|
||||
int rw_timeout;
|
||||
int trunc;
|
||||
char *priv_key;
|
||||
int verify;
|
||||
} LIBSSHContext;
|
||||
|
||||
#if LIBSSH_VERSION_INT < SSH_VERSION_INT(0, 8, 0)
|
||||
#define ssh_session_is_known_server ssh_is_server_known
|
||||
#define SSH_KNOWN_HOSTS_OK SSH_SERVER_KNOWN_OK
|
||||
#define SSH_KNOWN_HOSTS_CHANGED SSH_SERVER_KNOWN_CHANGED
|
||||
#define SSH_KNOWN_HOSTS_OTHER SSH_SERVER_FOUND_OTHER
|
||||
#define SSH_KNOWN_HOSTS_UNKNOWN SSH_SERVER_NOT_KNOWN
|
||||
#define SSH_KNOWN_HOSTS_NOT_FOUND SSH_SERVER_FILE_NOT_FOUND
|
||||
#endif
|
||||
|
||||
static av_cold int libssh_verify_hostkey(LIBSSHContext *libssh)
|
||||
{
|
||||
int strict = 1;
|
||||
|
||||
ssh_options_set(libssh->session, SSH_OPTIONS_STRICTHOSTKEYCHECK, &strict);
|
||||
switch (ssh_session_is_known_server(libssh->session)) {
|
||||
case SSH_KNOWN_HOSTS_OK:
|
||||
return 0;
|
||||
case SSH_KNOWN_HOSTS_CHANGED:
|
||||
av_log(libssh, AV_LOG_ERROR, "Host key for server has changed; "
|
||||
"possible man-in-the-middle attack, refusing to connect.\n");
|
||||
return AVERROR(EACCES);
|
||||
case SSH_KNOWN_HOSTS_OTHER:
|
||||
av_log(libssh, AV_LOG_ERROR, "Host key of a type different from the one "
|
||||
"in the known_hosts file; refusing to connect.\n");
|
||||
return AVERROR(EACCES);
|
||||
case SSH_KNOWN_HOSTS_UNKNOWN:
|
||||
case SSH_KNOWN_HOSTS_NOT_FOUND:
|
||||
av_log(libssh, AV_LOG_ERROR, "Server is not a known host; refusing to connect.\n");
|
||||
return AVERROR(EACCES);
|
||||
default:
|
||||
av_log(libssh, AV_LOG_ERROR, "Failed to check the server host key: %s\n",
|
||||
ssh_get_error(libssh->session));
|
||||
return AVERROR(EIO);
|
||||
}
|
||||
}
|
||||
|
||||
static av_cold int libssh_create_ssh_session(LIBSSHContext *libssh, const char* hostname, unsigned int port)
|
||||
{
|
||||
static const int verbosity = SSH_LOG_NOLOG;
|
||||
@@ -67,6 +104,12 @@ static av_cold int libssh_create_ssh_session(LIBSSHContext *libssh, const char*
|
||||
return AVERROR(EIO);
|
||||
}
|
||||
|
||||
if (libssh->verify) {
|
||||
int ret = libssh_verify_hostkey(libssh);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -477,6 +520,7 @@ static const AVOption options[] = {
|
||||
{"timeout", "set timeout of socket I/O operations", OFFSET(rw_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, D|E },
|
||||
{"truncate", "Truncate existing files on write", OFFSET(trunc), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, E },
|
||||
{"private_key", "set path to private key", OFFSET(priv_key), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D|E },
|
||||
{"verify", "verify the server host key against the known_hosts file", OFFSET(verify), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, D|E },
|
||||
{NULL}
|
||||
};
|
||||
|
||||
|
||||
Reference in new issue
Block a user