diff options
-rw-r--r-- | include/libssh/bind.h | 2 | ||||
-rw-r--r-- | include/libssh/session.h | 1 | ||||
-rw-r--r-- | src/bind.c | 35 | ||||
-rw-r--r-- | src/server.c | 55 |
4 files changed, 80 insertions, 13 deletions
diff --git a/include/libssh/bind.h b/include/libssh/bind.h index b2b856a..2078d44 100644 --- a/include/libssh/bind.h +++ b/include/libssh/bind.h @@ -34,8 +34,10 @@ struct ssh_bind_struct { /* options */ char *wanted_methods[10]; char *banner; + char *ecdsakey; char *dsakey; char *rsakey; + ssh_key ecdsa; ssh_key dsa; ssh_key rsa; char *bindaddr; diff --git a/include/libssh/session.h b/include/libssh/session.h index 20c94da..4bb0753 100644 --- a/include/libssh/session.h +++ b/include/libssh/session.h @@ -141,6 +141,7 @@ struct ssh_session_struct { struct { ssh_key rsa_key; ssh_key dsa_key; + ssh_key ecdsa_key; /* The type of host key wanted by client */ enum ssh_keytypes_e hostkey; @@ -165,12 +165,36 @@ int ssh_bind_listen(ssh_bind sshbind) { return -1; } - if (sshbind->dsakey == NULL && sshbind->rsakey == NULL) { + if (sshbind->ecdsakey == NULL && + sshbind->dsakey == NULL && + sshbind->rsakey == NULL) { ssh_set_error(sshbind, SSH_FATAL, "DSA or RSA host key file must be set before listen()"); return SSH_ERROR; } +#ifdef HAVE_ECC + if (sshbind->ecdsakey) { + rc = ssh_pki_import_privkey_file(sshbind->ecdsakey, + NULL, + NULL, + NULL, + &sshbind->ecdsa); + if (rc == SSH_ERROR) { + ssh_set_error(sshbind, SSH_FATAL, + "Failed to import private ECDSA host key"); + return SSH_ERROR; + } + + if (ssh_key_type(sshbind->ecdsa) != SSH_KEYTYPE_ECDSA) { + ssh_set_error(sshbind, SSH_FATAL, + "The ECDSA host key has the wrong type"); + ssh_key_free(sshbind->ecdsa); + return SSH_ERROR; + } + } +#endif + if (sshbind->dsakey) { rc = ssh_pki_import_privkey_file(sshbind->dsakey, NULL, @@ -385,6 +409,15 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd){ ssh_socket_set_fd(session->socket, fd); ssh_socket_get_poll_handle_out(session->socket); +#ifdef HAVE_ECC + if (sshbind->ecdsa) { + session->srv.ecdsa_key = ssh_key_dup(sshbind->ecdsa); + if (session->srv.ecdsa_key == NULL) { + ssh_set_error_oom(sshbind); + return SSH_ERROR; + } + } +#endif if (sshbind->dsa) { session->srv.dsa_key = ssh_key_dup(sshbind->dsa); if (session->srv.dsa_key == NULL) { diff --git a/src/server.c b/src/server.c index 5f1d823..ac3fec3 100644 --- a/src/server.c +++ b/src/server.c @@ -84,24 +84,47 @@ static int dh_handshake_server(ssh_session session); static int server_set_kex(ssh_session session) { struct ssh_kex_struct *server = &session->next_crypto->server_kex; - int i, j; + int i, j, rc; const char *wanted; + char hostkeys[64] = {0}; + enum ssh_keytypes_e keytype; + size_t len; ZERO_STRUCTP(server); ssh_get_random(server->cookie, 16, 0); - if (session->srv.dsa_key != NULL && session->srv.rsa_key != NULL) { - if (ssh_options_set_algo(session, SSH_HOSTKEYS, - "ssh-dss,ssh-rsa") < 0) { - return -1; - } - } else if (session->srv.dsa_key != NULL) { - if (ssh_options_set_algo(session, SSH_HOSTKEYS, "ssh-dss") < 0) { + +#ifdef HAVE_ECC + if (session->srv.ecdsa_key != NULL) { + keytype = ssh_key_type(session->srv.ecdsa_key); + + snprintf(hostkeys, sizeof(hostkeys), + "%s", session->srv.ecdsa_key->type_c); + } +#endif + if (session->srv.dsa_key != NULL) { + len = strlen(hostkeys); + keytype = ssh_key_type(session->srv.dsa_key); + + snprintf(hostkeys + len, sizeof(hostkeys) - len, + ",%s", ssh_key_type_to_char(keytype)); + } + if (session->srv.rsa_key != NULL) { + len = strlen(hostkeys); + keytype = ssh_key_type(session->srv.rsa_key); + + snprintf(hostkeys + len, sizeof(hostkeys) - len, + ",%s", ssh_key_type_to_char(keytype)); + } + + if (strlen(hostkeys) == 0) { return -1; - } - } else { - if (ssh_options_set_algo(session, SSH_HOSTKEYS, "ssh-rsa") < 0) { + } + + rc = ssh_options_set_algo(session, + SSH_HOSTKEYS, + hostkeys[0] == ',' ? hostkeys + 1 : hostkeys); + if (rc < 0) { return -1; - } } for (i = 0; i < 10; i++) { @@ -186,6 +209,8 @@ int ssh_get_key_params(ssh_session session, ssh_key *privkey){ *privkey = session->srv.rsa_key; break; case SSH_KEYTYPE_ECDSA: + *privkey = session->srv.ecdsa_key; + break; case SSH_KEYTYPE_UNKNOWN: *privkey = NULL; } @@ -263,6 +288,12 @@ static int dh_handshake_server(ssh_session session) { ssh_key_free(session->srv.dsa_key); session->srv.dsa_key = NULL; } +#ifdef HAVE_ECC + if (session->srv.ecdsa_key) { + ssh_key_free(session->srv.ecdsa_key); + session->srv.ecdsa_key = NULL; + } +#endif if (buffer_add_u8(session->out_buffer, SSH2_MSG_KEXDH_REPLY) < 0 || buffer_add_ssh_string(session->out_buffer, |