@@ -467,56 +467,54 @@ static int load_known_hosts(LIBSSH2_KNOWNHOSTS **hosts, LIBSSH2_SESSION *session
467
467
return error ;
468
468
}
469
469
470
- static const char * hostkey_type_to_string (int type )
470
+ static void add_hostkey_pref_if_avail (
471
+ LIBSSH2_KNOWNHOSTS * known_hosts ,
472
+ const char * hostname ,
473
+ int port ,
474
+ git_str * prefs ,
475
+ int type ,
476
+ const char * type_name )
471
477
{
472
- switch (type ) {
473
- case LIBSSH2_KNOWNHOST_KEY_SSHRSA :
474
- return "ssh-rsa" ;
475
- case LIBSSH2_KNOWNHOST_KEY_SSHDSS :
476
- return "ssh-dss" ;
477
- #ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_256
478
- case LIBSSH2_KNOWNHOST_KEY_ECDSA_256 :
479
- return "ecdsa-sha2-nistp256" ;
480
- case LIBSSH2_KNOWNHOST_KEY_ECDSA_384 :
481
- return "ecdsa-sha2-nistp384" ;
482
- case LIBSSH2_KNOWNHOST_KEY_ECDSA_521 :
483
- return "ecdsa-sha2-nistp521" ;
484
- #endif
485
- #ifdef LIBSSH2_KNOWNHOST_KEY_ED25519
486
- case LIBSSH2_KNOWNHOST_KEY_ED25519 :
487
- return "ssh-ed25519" ;
488
- #endif
489
- }
478
+ struct libssh2_knownhost * host = NULL ;
479
+ const char key = '\0' ;
480
+ int mask = LIBSSH2_KNOWNHOST_TYPE_PLAIN | LIBSSH2_KNOWNHOST_KEYENC_RAW | type ;
481
+ int error ;
490
482
491
- return NULL ;
483
+ error = libssh2_knownhost_checkp (known_hosts , hostname , port , & key , 1 , mask , & host );
484
+ if (error == LIBSSH2_KNOWNHOST_CHECK_MISMATCH ) {
485
+ if (git_str_len (prefs ) > 0 ) {
486
+ git_str_putc (prefs , ',' );
487
+ }
488
+ git_str_puts (prefs , type_name );
489
+ }
492
490
}
493
491
494
492
/*
495
493
* We figure out what kind of key we want to ask the remote for by trying to
496
494
* look it up with a nonsense key and using that mismatch to figure out what key
497
495
* we do have stored for the host.
498
496
*
499
- * Returns the string to pass to libssh2_session_method_pref or NULL if we were
500
- * unable to find anything or an error happened.
497
+ * Populates prefs with the string to pass to libssh2_session_method_pref.
501
498
*/
502
- static const char * find_hostkey_preference (LIBSSH2_KNOWNHOSTS * known_hosts , const char * hostname , int port )
499
+ static void find_hostkey_preference (
500
+ LIBSSH2_KNOWNHOSTS * known_hosts ,
501
+ const char * hostname ,
502
+ int port ,
503
+ git_str * prefs )
503
504
{
504
- struct libssh2_knownhost * host = NULL ;
505
- /* Specify no key type so we don't filter on that */
506
- int type = LIBSSH2_KNOWNHOST_TYPE_PLAIN | LIBSSH2_KNOWNHOST_KEYENC_RAW ;
507
- const char key = '\0' ;
508
- int error ;
509
-
510
505
/*
511
- * In case of mismatch, we can find the type of key from known_hosts in
512
- * the returned host's information as it means that an entry was found
513
- * but our nonsense key obviously didn't match.
506
+ * The order here is important as it indicates the priority of what will
507
+ * be preferred.
514
508
*/
515
- error = libssh2_knownhost_checkp (known_hosts , hostname , port , & key , 1 , type , & host );
516
- if (error == LIBSSH2_KNOWNHOST_CHECK_MISMATCH )
517
- return hostkey_type_to_string (host -> typemask & LIBSSH2_KNOWNHOST_KEY_MASK );
518
-
519
- return NULL ;
509
+ #ifdef LIBSSH2_KNOWNHOST_KEY_ED25519
510
+ add_hostkey_pref_if_avail (known_hosts , hostname , port , prefs , LIBSSH2_KNOWNHOST_KEY_ED25519 , "ssh-ed25519" );
511
+ #endif
512
+ #ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_256
513
+ add_hostkey_pref_if_avail (known_hosts , hostname , port , prefs , LIBSSH2_KNOWNHOST_KEY_ECDSA_256 , "ecdsa-sha2-nistp256" );
514
+ add_hostkey_pref_if_avail (known_hosts , hostname , port , prefs , LIBSSH2_KNOWNHOST_KEY_ECDSA_384 , "ecdsa-sha2-nistp384" );
515
+ add_hostkey_pref_if_avail (known_hosts , hostname , port , prefs , LIBSSH2_KNOWNHOST_KEY_ECDSA_521 , "ecdsa-sha2-nistp521" );
516
+ #endif
517
+ add_hostkey_pref_if_avail (known_hosts , hostname , port , prefs , LIBSSH2_KNOWNHOST_KEY_SSHRSA , "ssh-rsa" );
520
518
}
521
519
522
520
static int _git_ssh_session_create (
@@ -547,16 +545,18 @@ static int _git_ssh_session_create(
547
545
return -1 ;
548
546
}
549
547
550
- if ((keytype = find_hostkey_preference (known_hosts , hostname , port )) != NULL ) {
548
+ git_str prefs = GIT_STR_INIT ;
549
+ find_hostkey_preference (known_hosts , hostname , port , & prefs );
550
+ if (git_str_len (& prefs ) > 0 ) {
551
551
do {
552
- rc = libssh2_session_method_pref (s , LIBSSH2_METHOD_HOSTKEY , keytype );
552
+ rc = libssh2_session_method_pref (s , LIBSSH2_METHOD_HOSTKEY , git_str_cstr ( & prefs ) );
553
553
} while (LIBSSH2_ERROR_EAGAIN == rc || LIBSSH2_ERROR_TIMEOUT == rc );
554
554
if (rc != LIBSSH2_ERROR_NONE ) {
555
555
ssh_error (s , "failed to set hostkey preference" );
556
556
goto on_error ;
557
557
}
558
558
}
559
-
559
+ git_str_dispose ( & prefs );
560
560
561
561
do {
562
562
rc = libssh2_session_handshake (s , socket -> s );
0 commit comments