Based on a patch brought by Johnny Luong, libcurl now offers
CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 and the curl tool --hostpubmd5. They both make the SCP or SFTP connection verify the remote host's md5 checksum of the public key before doing a connect, to reduce the risk of a man-in-the-middle attack.
This commit is contained in:
parent
15b8da1980
commit
51c6a5d43b
7
CHANGES
7
CHANGES
@ -6,6 +6,13 @@
|
||||
|
||||
Changelog
|
||||
|
||||
Daniel S (3 October 2007)
|
||||
- Based on a patch brought by Johnny Luong, libcurl now offers
|
||||
CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 and the curl tool --hostpubmd5. They both
|
||||
make the SCP or SFTP connection verify the remote host's md5 checksum of the
|
||||
public key before doing a connect, to reduce the risk of a man-in-the-middle
|
||||
attack.
|
||||
|
||||
Daniel S (2 October 2007)
|
||||
- libcurl now handles chunked-encoded CONNECT responses
|
||||
|
||||
|
@ -2,8 +2,8 @@ Curl and libcurl 7.17.1
|
||||
|
||||
Public curl release number: 102
|
||||
Releases counted from the very beginning: 128
|
||||
Available command line options: 120
|
||||
Available curl_easy_setopt() options: 144
|
||||
Available command line options: 121
|
||||
Available curl_easy_setopt() options: 145
|
||||
Number of public functions in libcurl: 55
|
||||
Amount of public web site mirrors: 42
|
||||
Number of known libcurl bindings: 36
|
||||
@ -16,6 +16,7 @@ This release includes the following changes:
|
||||
o added --proxy-negotiate
|
||||
o added --post301 and CURLOPT_POST301
|
||||
o builds with c-ares 1.5.0
|
||||
o added CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 and --hostpubmd5
|
||||
|
||||
This release includes the following bugfixes:
|
||||
|
||||
@ -47,6 +48,6 @@ This release would not have looked like this without help, code, reports and
|
||||
advice from friends like these:
|
||||
|
||||
Dan Fandrich, Michal Marek, Günter Knauf, Rob Crittenden, Immanuel Gregoire,
|
||||
Mark Davies, Max Katsev, Philip Langdale, Alex Fishman
|
||||
Mark Davies, Max Katsev, Philip Langdale, Alex Fishman, Johnny Luong
|
||||
|
||||
Thanks! (and sorry if I forgot to mention someone)
|
||||
|
@ -544,6 +544,11 @@ for you.
|
||||
See also the \fI-A/--user-agent\fP and \fI-e/--referer\fP options.
|
||||
|
||||
This option can be used multiple times to add/replace/remove multiple headers.
|
||||
.IP "--hostpubmd5"
|
||||
Pass a string containing 32 hexadecimal digits. The string should be the 128
|
||||
bit MD5 cheksum of the remote host's public key, curl will refuse the
|
||||
connection with the host unless the md5sums match. This option is only for SCP
|
||||
and SFTP transfers. (Added in 7.17.1)
|
||||
.IP "--ignore-content-length"
|
||||
(HTTP)
|
||||
Ignore the Content-Length header. This is particularly useful for servers
|
||||
|
@ -1411,6 +1411,11 @@ Pass a long set to a bitmask consisting of one or more of
|
||||
CURLSSH_AUTH_PUBLICKEY, CURLSSH_AUTH_PASSWORD, CURLSSH_AUTH_HOST,
|
||||
CURLSSH_AUTH_KEYBOARD. Set CURLSSH_AUTH_ANY to let libcurl pick one.
|
||||
(Added in 7.16.1)
|
||||
.IP CURLOPT_SSH_HOST_PUBLIC_KEY_MD5
|
||||
Pass a char * pointing to a string containing 32 hexadecimal digits. The
|
||||
string should be the 128 bit MD5 cheksum of the remote host's public key, and
|
||||
libcurl will reject the connection to the host unless the md5sums match. This
|
||||
option is only for SCP and SFTP transfers. (Added in 7.17.1)
|
||||
.IP CURLOPT_SSH_PUBLIC_KEYFILE
|
||||
Pass a char * pointing to a file name for your public key. If not used,
|
||||
libcurl defaults to using \fB~/.ssh/id_dsa.pub\fP.
|
||||
|
@ -419,7 +419,7 @@ typedef enum {
|
||||
/* These are scheduled to disappear by 2009 */
|
||||
|
||||
/* The following were added in 7.17.0 */
|
||||
#define CURLE_OBSOLETE CURLE_OBSOLETE50 /* noone should be using this! */
|
||||
#define CURLE_OBSOLETE CURLE_OBSOLETE50 /* noone should be using this! */
|
||||
#define CURLE_BAD_PASSWORD_ENTERED CURLE_OBSOLETE46
|
||||
#define CURLE_BAD_CALLING_ORDER CURLE_OBSOLETE44
|
||||
#define CURLE_FTP_USER_PASSWORD_INCORRECT CURLE_OBSOLETE10
|
||||
@ -438,7 +438,7 @@ typedef enum {
|
||||
#define CURLE_FTP_QUOTE_ERROR CURLE_QUOTE_ERROR
|
||||
#define CURLE_TFTP_DISKFULL CURLE_REMOTE_DISK_FULL
|
||||
#define CURLE_TFTP_EXISTS CURLE_REMOTE_FILE_EXISTS
|
||||
#define CURLE_HTTP_RANGE_ERROR CURLE_RANGE_ERROR
|
||||
#define CURLE_HTTP_RANGE_ERROR CURLE_RANGE_ERROR
|
||||
#define CURLE_FTP_SSL_FAILED CURLE_USE_SSL_FAILED
|
||||
|
||||
/* The following were added earlier */
|
||||
@ -1127,6 +1127,9 @@ typedef enum {
|
||||
/* Obey RFC 2616/10.3.2 and keep POSTs as POSTs after a 301 */
|
||||
CINIT(POST301, LONG, 161),
|
||||
|
||||
/* used by scp/sftp to verify the host's public key */
|
||||
CINIT(SSH_HOST_PUBLIC_KEY_MD5, OBJECTPOINT, 162),
|
||||
|
||||
CURLOPT_LASTENTRY /* the last unused */
|
||||
} CURLoption;
|
||||
|
||||
@ -1137,7 +1140,7 @@ typedef enum {
|
||||
/* These are scheduled to disappear by 2009 */
|
||||
|
||||
/* The following were added in 7.17.0 */
|
||||
#define CURLOPT_SSLKEYPASSWD CURLOPT_KEYPASSWD
|
||||
#define CURLOPT_SSLKEYPASSWD CURLOPT_KEYPASSWD
|
||||
#define CURLOPT_FTPAPPEND CURLOPT_APPEND
|
||||
#define CURLOPT_FTPLISTONLY CURLOPT_DIRLISTONLY
|
||||
#define CURLOPT_FTP_SSL CURLOPT_USE_SSL
|
||||
|
27
lib/ssh.c
27
lib/ssh.c
@ -310,7 +310,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
|
||||
#ifdef CURL_LIBSSH2_DEBUG
|
||||
const char *fingerprint;
|
||||
#endif /* CURL_LIBSSH2_DEBUG */
|
||||
int rc;
|
||||
const char *host_public_key_md5;
|
||||
int rc,i;
|
||||
long err;
|
||||
|
||||
switch(sshc->state) {
|
||||
@ -351,6 +352,30 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
|
||||
infof(data, "\n");
|
||||
#endif /* CURL_LIBSSH2_DEBUG */
|
||||
|
||||
/* Before we authenticate we check the hostkey's MD5 fingerprint
|
||||
* against a known fingerprint, if available. This implementation pulls
|
||||
* it from the curl option.
|
||||
*/
|
||||
if (data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5] &&
|
||||
strlen(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]) == 32)
|
||||
{
|
||||
char buf[33];
|
||||
host_public_key_md5 = libssh2_hostkey_hash(sftp_scp->ssh_session,
|
||||
LIBSSH2_HOSTKEY_HASH_MD5);
|
||||
for (i = 0; i < 16; i++)
|
||||
snprintf(&buf[i*2], 3, "%02x",
|
||||
(unsigned char) host_public_key_md5[i]);
|
||||
if(!strequal(buf, data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5])) {
|
||||
failf(data,
|
||||
"Denied establishing ssh session: mismatch md5 fingerprint. "
|
||||
"Remote %s is not equal to %s",
|
||||
buf, data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]);
|
||||
state(conn, SSH_SESSION_FREE);
|
||||
sshc->actualCode = CURLE_FAILED_INIT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
state(conn, SSH_AUTHLIST);
|
||||
break;
|
||||
|
||||
|
@ -1836,7 +1836,14 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
|
||||
result = Curl_setstropt(&data->set.str[STRING_SSH_PRIVATE_KEY],
|
||||
va_arg(param, char *));
|
||||
break;
|
||||
|
||||
case CURLOPT_SSH_HOST_PUBLIC_KEY_MD5:
|
||||
/*
|
||||
* Option to allow for the MD5 of the host public key to be checked
|
||||
* for validation purposes.
|
||||
*/
|
||||
result = Curl_setstropt(&data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5],
|
||||
va_arg(param, char *));
|
||||
break;
|
||||
case CURLOPT_HTTP_TRANSFER_DECODING:
|
||||
/*
|
||||
* disable libcurl transfer encoding is used
|
||||
|
@ -1289,6 +1289,7 @@ enum dupstring {
|
||||
STRING_SSL_RANDOM_FILE, /* path to file containing "random" data */
|
||||
STRING_USERAGENT, /* User-Agent string */
|
||||
STRING_USERPWD, /* <user:password>, if used */
|
||||
STRING_SSH_HOST_PUBLIC_KEY_MD5, /* md5 of host public key in ascii hex */
|
||||
|
||||
/* -- end of strings -- */
|
||||
STRING_LAST /* not used, just an end-of-list marker */
|
||||
|
14
src/main.c
14
src/main.c
@ -407,6 +407,7 @@ struct Configurable {
|
||||
char *key_type;
|
||||
char *key_passwd;
|
||||
char *pubkey;
|
||||
char *hostpubmd5;
|
||||
char *engine;
|
||||
bool list_engines;
|
||||
bool crlf;
|
||||
@ -639,6 +640,7 @@ static void help(void)
|
||||
" --cacert <file> CA certificate to verify peer against (SSL)",
|
||||
" --capath <directory> CA directory (made using c_rehash) to verify",
|
||||
" peer against (SSL)",
|
||||
" --hostpubmd5 <md5> Hex encoded MD5 string of the host public key. (SSH)",
|
||||
" --ciphers <list> SSL ciphers to use (SSL)",
|
||||
" --compressed Request compressed response (using deflate or gzip)",
|
||||
" --connect-timeout <seconds> Maximum time allowed for connection",
|
||||
@ -1541,6 +1543,7 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
|
||||
{"Ef","engine", TRUE},
|
||||
{"Eg","capath ", TRUE},
|
||||
{"Eh","pubkey", TRUE},
|
||||
{"Ei", "hostpubmd5", TRUE},
|
||||
{"f", "fail", FALSE},
|
||||
{"F", "form", TRUE},
|
||||
{"Fs","form-string", TRUE},
|
||||
@ -2159,6 +2162,11 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
|
||||
case 'h': /* --pubkey public key file */
|
||||
GetStr(&config->pubkey, nextarg);
|
||||
break;
|
||||
case 'i': /* --hostpubmd5 md5 of the host public key */
|
||||
GetStr(&config->hostpubmd5, nextarg);
|
||||
if (!config->hostpubmd5 || strlen(config->hostpubmd5) != 32)
|
||||
return PARAM_BAD_USE;
|
||||
break;
|
||||
default: /* certificate file */
|
||||
{
|
||||
char *ptr = strchr(nextarg, ':');
|
||||
@ -4206,6 +4214,12 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
|
||||
my_setopt(curl, CURLOPT_SSH_PRIVATE_KEYFILE, config->key);
|
||||
my_setopt(curl, CURLOPT_SSH_PUBLIC_KEYFILE, config->pubkey);
|
||||
|
||||
/* SSH host key md5 checking allows us to fail if we are
|
||||
* not talking to who we think we should
|
||||
*/
|
||||
my_setopt(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_MD5, config->hostpubmd5);
|
||||
|
||||
|
||||
/* default to strict verifyhost */
|
||||
my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2);
|
||||
if(config->cacert || config->capath) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user