aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Schneider <asn@cryptomilk.org>2012-02-15 09:23:07 +0100
committerAndreas Schneider <asn@cryptomilk.org>2012-02-19 18:49:07 +0100
commit1973e833f2f8987c7be494e5dff86008a8557758 (patch)
tree5575fbdd4919c3a7acc60127987820482a015126
parent387d9e485546a4f7e02e89fdcd097e700cf9ca81 (diff)
downloadlibssh-1973e833f2f8987c7be494e5dff86008a8557758.tar.gz
libssh-1973e833f2f8987c7be494e5dff86008a8557758.tar.xz
libssh-1973e833f2f8987c7be494e5dff86008a8557758.zip
server: Add ecdsa hostkey support.
-rw-r--r--include/libssh/bind.h2
-rw-r--r--include/libssh/session.h1
-rw-r--r--src/bind.c35
-rw-r--r--src/server.c55
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;
diff --git a/src/bind.c b/src/bind.c
index d287a7d..3da4988 100644
--- a/src/bind.c
+++ b/src/bind.c
@@ -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,