1
0
mirror of https://github.com/moparisthebest/curl synced 2024-11-10 11:35:07 -05:00

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:
Daniel Stenberg 2007-10-03 08:00:42 +00:00
parent 15b8da1980
commit 51c6a5d43b
9 changed files with 76 additions and 8 deletions

View File

@ -6,6 +6,13 @@
Changelog 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) Daniel S (2 October 2007)
- libcurl now handles chunked-encoded CONNECT responses - libcurl now handles chunked-encoded CONNECT responses

View File

@ -2,8 +2,8 @@ Curl and libcurl 7.17.1
Public curl release number: 102 Public curl release number: 102
Releases counted from the very beginning: 128 Releases counted from the very beginning: 128
Available command line options: 120 Available command line options: 121
Available curl_easy_setopt() options: 144 Available curl_easy_setopt() options: 145
Number of public functions in libcurl: 55 Number of public functions in libcurl: 55
Amount of public web site mirrors: 42 Amount of public web site mirrors: 42
Number of known libcurl bindings: 36 Number of known libcurl bindings: 36
@ -16,6 +16,7 @@ This release includes the following changes:
o added --proxy-negotiate o added --proxy-negotiate
o added --post301 and CURLOPT_POST301 o added --post301 and CURLOPT_POST301
o builds with c-ares 1.5.0 o builds with c-ares 1.5.0
o added CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 and --hostpubmd5
This release includes the following bugfixes: 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: advice from friends like these:
Dan Fandrich, Michal Marek, Günter Knauf, Rob Crittenden, Immanuel Gregoire, 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) Thanks! (and sorry if I forgot to mention someone)

View File

@ -544,6 +544,11 @@ for you.
See also the \fI-A/--user-agent\fP and \fI-e/--referer\fP options. 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. 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" .IP "--ignore-content-length"
(HTTP) (HTTP)
Ignore the Content-Length header. This is particularly useful for servers Ignore the Content-Length header. This is particularly useful for servers

View File

@ -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_PUBLICKEY, CURLSSH_AUTH_PASSWORD, CURLSSH_AUTH_HOST,
CURLSSH_AUTH_KEYBOARD. Set CURLSSH_AUTH_ANY to let libcurl pick one. CURLSSH_AUTH_KEYBOARD. Set CURLSSH_AUTH_ANY to let libcurl pick one.
(Added in 7.16.1) (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 .IP CURLOPT_SSH_PUBLIC_KEYFILE
Pass a char * pointing to a file name for your public key. If not used, 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. libcurl defaults to using \fB~/.ssh/id_dsa.pub\fP.

View File

@ -1127,6 +1127,9 @@ typedef enum {
/* Obey RFC 2616/10.3.2 and keep POSTs as POSTs after a 301 */ /* Obey RFC 2616/10.3.2 and keep POSTs as POSTs after a 301 */
CINIT(POST301, LONG, 161), 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 */ CURLOPT_LASTENTRY /* the last unused */
} CURLoption; } CURLoption;

View File

@ -310,7 +310,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
#ifdef CURL_LIBSSH2_DEBUG #ifdef CURL_LIBSSH2_DEBUG
const char *fingerprint; const char *fingerprint;
#endif /* CURL_LIBSSH2_DEBUG */ #endif /* CURL_LIBSSH2_DEBUG */
int rc; const char *host_public_key_md5;
int rc,i;
long err; long err;
switch(sshc->state) { switch(sshc->state) {
@ -351,6 +352,30 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
infof(data, "\n"); infof(data, "\n");
#endif /* CURL_LIBSSH2_DEBUG */ #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); state(conn, SSH_AUTHLIST);
break; break;

View File

@ -1836,7 +1836,14 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
result = Curl_setstropt(&data->set.str[STRING_SSH_PRIVATE_KEY], result = Curl_setstropt(&data->set.str[STRING_SSH_PRIVATE_KEY],
va_arg(param, char *)); va_arg(param, char *));
break; 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: case CURLOPT_HTTP_TRANSFER_DECODING:
/* /*
* disable libcurl transfer encoding is used * disable libcurl transfer encoding is used

View File

@ -1289,6 +1289,7 @@ enum dupstring {
STRING_SSL_RANDOM_FILE, /* path to file containing "random" data */ STRING_SSL_RANDOM_FILE, /* path to file containing "random" data */
STRING_USERAGENT, /* User-Agent string */ STRING_USERAGENT, /* User-Agent string */
STRING_USERPWD, /* <user:password>, if used */ STRING_USERPWD, /* <user:password>, if used */
STRING_SSH_HOST_PUBLIC_KEY_MD5, /* md5 of host public key in ascii hex */
/* -- end of strings -- */ /* -- end of strings -- */
STRING_LAST /* not used, just an end-of-list marker */ STRING_LAST /* not used, just an end-of-list marker */

View File

@ -407,6 +407,7 @@ struct Configurable {
char *key_type; char *key_type;
char *key_passwd; char *key_passwd;
char *pubkey; char *pubkey;
char *hostpubmd5;
char *engine; char *engine;
bool list_engines; bool list_engines;
bool crlf; bool crlf;
@ -639,6 +640,7 @@ static void help(void)
" --cacert <file> CA certificate to verify peer against (SSL)", " --cacert <file> CA certificate to verify peer against (SSL)",
" --capath <directory> CA directory (made using c_rehash) to verify", " --capath <directory> CA directory (made using c_rehash) to verify",
" peer against (SSL)", " peer against (SSL)",
" --hostpubmd5 <md5> Hex encoded MD5 string of the host public key. (SSH)",
" --ciphers <list> SSL ciphers to use (SSL)", " --ciphers <list> SSL ciphers to use (SSL)",
" --compressed Request compressed response (using deflate or gzip)", " --compressed Request compressed response (using deflate or gzip)",
" --connect-timeout <seconds> Maximum time allowed for connection", " --connect-timeout <seconds> Maximum time allowed for connection",
@ -1541,6 +1543,7 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
{"Ef","engine", TRUE}, {"Ef","engine", TRUE},
{"Eg","capath ", TRUE}, {"Eg","capath ", TRUE},
{"Eh","pubkey", TRUE}, {"Eh","pubkey", TRUE},
{"Ei", "hostpubmd5", TRUE},
{"f", "fail", FALSE}, {"f", "fail", FALSE},
{"F", "form", TRUE}, {"F", "form", TRUE},
{"Fs","form-string", TRUE}, {"Fs","form-string", TRUE},
@ -2159,6 +2162,11 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
case 'h': /* --pubkey public key file */ case 'h': /* --pubkey public key file */
GetStr(&config->pubkey, nextarg); GetStr(&config->pubkey, nextarg);
break; 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 */ default: /* certificate file */
{ {
char *ptr = strchr(nextarg, ':'); 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_PRIVATE_KEYFILE, config->key);
my_setopt(curl, CURLOPT_SSH_PUBLIC_KEYFILE, config->pubkey); 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 */ /* default to strict verifyhost */
my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2); my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2);
if(config->cacert || config->capath) { if(config->cacert || config->capath) {