diff --git a/.gitignore b/.gitignore
index cedfe7a..9130fdb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,2 @@
-SOURCES/libssh-0.8.5.tar.xz
+SOURCES/libssh-0.9.0.tar.xz
 SOURCES/libssh.keyring
diff --git a/.libssh.metadata b/.libssh.metadata
index 19fd4e7..2c4bf88 100644
--- a/.libssh.metadata
+++ b/.libssh.metadata
@@ -1,2 +1,2 @@
-b5564774f986e396a7288a593595455bf10d9ce8 SOURCES/libssh-0.8.5.tar.xz
+570bffef68af6c1211673bc9a8036c9265935b2b SOURCES/libssh-0.9.0.tar.xz
 3f2ab0bca02893402ba0ad172a6bd44456a65f86 SOURCES/libssh.keyring
diff --git a/SOURCES/libssh-0.8.5-allow-kex-init.patch b/SOURCES/libssh-0.8.5-allow-kex-init.patch
deleted file mode 100644
index 511283e..0000000
--- a/SOURCES/libssh-0.8.5-allow-kex-init.patch
+++ /dev/null
@@ -1,39 +0,0 @@
-From e6e8335847d4870c99c07f511b4a24ae9e053326 Mon Sep 17 00:00:00 2001
-From: Jakub Jelen <jjelen@redhat.com>
-Date: Thu, 15 Nov 2018 11:03:56 +0100
-Subject: [PATCH] packet: Adjust the packet filter to allow client-initialized
- rekey
-
-If the rekey is initialized by client, it sends the first KEXINIT
-message, changes to the INIT_SENT state and waits for the KEXINIT
-message from the server. This was not covered in the current filter.
-
-Signed-off-by: Jakub Jelen <jjelen@redhat.com>
-Reviewed-by: Daiki Ueno <dueno@redhat.com>
----
- src/packet.c | 2 ++
- 1 file changed, 2 insertions(+)
-
-diff --git a/src/packet.c b/src/packet.c
-index 9b7b9b8f..86314961 100644
---- a/src/packet.c
-+++ b/src/packet.c
-@@ -292,6 +292,7 @@ static enum ssh_packet_filter_result_e ssh_packet_incoming_filter(ssh_session se
-          * - session_state == SSH_SESSION_STATE_AUTHENTICATED
-          *   or session_state == SSH_SESSION_STATE_INITIAL_KEX
-          * - dh_handshake_state == DH_STATE_INIT
-+         *   or dh_handshake_state == DH_STATE_INIT_SENT (re-exchange)
-          *   or dh_handshake_state == DH_STATE_FINISHED (re-exchange)
-          *
-          * Transitions:
-@@ -310,6 +311,7 @@ static enum ssh_packet_filter_result_e ssh_packet_incoming_filter(ssh_session se
-         }
- 
-         if ((session->dh_handshake_state != DH_STATE_INIT) &&
-+            (session->dh_handshake_state != DH_STATE_INIT_SENT) &&
-             (session->dh_handshake_state != DH_STATE_FINISHED))
-         {
-             rc = SSH_PACKET_DENIED;
--- 
-2.19.1
-
diff --git a/SOURCES/libssh-0.8.5-allow-msg-ext-info.patch b/SOURCES/libssh-0.8.5-allow-msg-ext-info.patch
deleted file mode 100644
index 37f3d19..0000000
--- a/SOURCES/libssh-0.8.5-allow-msg-ext-info.patch
+++ /dev/null
@@ -1,92 +0,0 @@
-From a6e055c42b34ec50f55606312b09ec2e14990416 Mon Sep 17 00:00:00 2001
-From: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
-Date: Fri, 7 Dec 2018 18:19:33 +0100
-Subject: [PATCH] packet: Allow SSH2_MSG_EXT_INFO when authenticated
-
-When the server requests rekey, it can send the SSH2_MSG_EXT_INFO.  This
-message was being filtered out by the packet filtering.  This includes a
-test to enforce the filtering rules for this packet type.
-
-Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
-Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
-(cherry picked from commit fe309ba43fb904da4385fc40a338ecc7482f8388)
----
- src/packet.c                            |  6 ++++-
- tests/unittests/torture_packet_filter.c | 31 +++++++++++++++++++++++++
- 2 files changed, 36 insertions(+), 1 deletion(-)
-
-diff --git a/src/packet.c b/src/packet.c
-index 72e3c096..61a44237 100644
---- a/src/packet.c
-+++ b/src/packet.c
-@@ -263,13 +263,17 @@ static enum ssh_packet_filter_result_e ssh_packet_incoming_filter(ssh_session se
-         /*
-          * States required:
-          * - session_state == SSH_SESSION_STATE_AUTHENTICATING
-+         *   or session->session_state == SSH_SESSION_STATE_AUTHENTICATED
-+         *   (re-exchange)
-          * - dh_handshake_state == DH_STATE_FINISHED
-          *
-          * Transitions:
-          * - None
-          * */
- 
--        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) {
-+        if ((session->session_state != SSH_SESSION_STATE_AUTHENTICATING) &&
-+            (session->session_state != SSH_SESSION_STATE_AUTHENTICATED))
-+        {
-             rc = SSH_PACKET_DENIED;
-             break;
-         }
-diff --git a/tests/unittests/torture_packet_filter.c b/tests/unittests/torture_packet_filter.c
-index 72cbc4cd..44ee3598 100644
---- a/tests/unittests/torture_packet_filter.c
-+++ b/tests/unittests/torture_packet_filter.c
-@@ -462,6 +462,36 @@ static void torture_packet_filter_check_auth_success(void **state)
-     assert_int_equal(rc, 0);
- }
- 
-+static void torture_packet_filter_check_msg_ext_info(void **state)
-+{
-+    int rc;
-+
-+    global_state accepted[] = {
-+        {
-+            .flags = (COMPARE_SESSION_STATE |
-+                    COMPARE_DH_STATE),
-+            .session = SSH_SESSION_STATE_AUTHENTICATING,
-+            .dh = DH_STATE_FINISHED,
-+        },
-+        {
-+            .flags = (COMPARE_SESSION_STATE |
-+                    COMPARE_DH_STATE),
-+            .session = SSH_SESSION_STATE_AUTHENTICATED,
-+            .dh = DH_STATE_FINISHED,
-+        },
-+    };
-+
-+    int accepted_count = 2;
-+
-+    /* Unused */
-+    (void) state;
-+
-+    rc = check_message_in_all_states(accepted, accepted_count,
-+            SSH2_MSG_EXT_INFO);
-+
-+    assert_int_equal(rc, 0);
-+}
-+
- static void torture_packet_filter_check_channel_open(void **state)
- {
-     int rc;
-@@ -492,6 +522,7 @@ int torture_run_tests(void)
-         cmocka_unit_test(torture_packet_filter_check_auth_success),
-         cmocka_unit_test(torture_packet_filter_check_channel_open),
-         cmocka_unit_test(torture_packet_filter_check_unfiltered),
-+        cmocka_unit_test(torture_packet_filter_check_msg_ext_info)
-     };
- 
-     ssh_init();
--- 
-2.19.1
-
diff --git a/SOURCES/libssh-0.8.5-ensure-ssh-session-fd-writable.patch b/SOURCES/libssh-0.8.5-ensure-ssh-session-fd-writable.patch
deleted file mode 100644
index f0e2d82..0000000
--- a/SOURCES/libssh-0.8.5-ensure-ssh-session-fd-writable.patch
+++ /dev/null
@@ -1,47 +0,0 @@
-From 7f1d30de47d67c03cf895f0d4d4e68daf9d396c5 Mon Sep 17 00:00:00 2001
-From: Sanne Raymaekers <sraymaek@redhat.com>
-Date: Fri, 26 Oct 2018 14:58:34 +0200
-Subject: [PATCH] tests: Ensure the ssh session fd is read-/writeable in
- torture_proxycommand
-
-Signed-off-by: Sanne Raymaekers <sraymaek@redhat.com>
-Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
-Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
-(cherry picked from commit 03c30e9c8ad34b3fa659a70e474a9b8cb248f85b)
-(cherry picked from commit 3de34944ad11bf4e22fc981562f32cb4b3b90ba9)
----
- tests/client/torture_proxycommand.c | 6 ++++++
- 1 file changed, 6 insertions(+)
-
-diff --git a/tests/client/torture_proxycommand.c b/tests/client/torture_proxycommand.c
-index ea1e1838..9608e663 100644
---- a/tests/client/torture_proxycommand.c
-+++ b/tests/client/torture_proxycommand.c
-@@ -9,6 +9,7 @@
- #include <sys/types.h>
- #include <pwd.h>
- #include <errno.h>
-+#include <fcntl.h>
- 
- static int sshd_setup(void **state)
- {
-@@ -61,11 +62,16 @@ static void torture_options_set_proxycommand(void **state) {
-     struct torture_state *s = *state;
-     ssh_session session = s->ssh.session;
-     int rc;
-+    socket_t fd;
- 
-     rc = ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, "nc 127.0.0.10 22");
-     assert_int_equal(rc, 0);
-     rc = ssh_connect(session);
-     assert_ssh_return_code(session, rc);
-+    fd = ssh_get_fd(session);
-+    assert_true(fd != SSH_INVALID_SOCKET);
-+    rc = fcntl(fd, F_GETFL);
-+    assert_int_equal(rc & O_RDWR, O_RDWR);
- }
- 
- static void torture_options_set_proxycommand_notexist(void **state) {
--- 
-2.19.1
-
diff --git a/SOURCES/libssh-0.8.5-make-sure-both-known-hosts-ready.patch b/SOURCES/libssh-0.8.5-make-sure-both-known-hosts-ready.patch
deleted file mode 100644
index 8206dc0..0000000
--- a/SOURCES/libssh-0.8.5-make-sure-both-known-hosts-ready.patch
+++ /dev/null
@@ -1,37 +0,0 @@
-From bed645ed5fca3ff776fd1997ec9d5c6b9065a7eb Mon Sep 17 00:00:00 2001
-From: Jakub Jelen <jjelen@redhat.com>
-Date: Tue, 30 Oct 2018 13:55:30 +0100
-Subject: [PATCH] knownhosts: Make sure we have both knownhosts files ready
-
-If either one is missing at this point, fill it with default vaules in
-ssh_options_apply().
-
-Previously, when setting up only knownhosts, global_knownhosts file
-was left pointing to NULL and the ssh_known_hosts_read_entries()
-was trying to open NULL file which is invalid.
-
-Signed-off-by: Jakub Jelen <jjelen@redhat.com>
-Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
-(cherry picked from commit 5159cd96e8b61c9f8f96786f70cf23167980b621)
-(cherry picked from commit a4b99eedf2f0f993f10c31d9bea0f1ad9fa7737e)
----
- src/knownhosts.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/src/knownhosts.c b/src/knownhosts.c
-index 23902a5f..546619aa 100644
---- a/src/knownhosts.c
-+++ b/src/knownhosts.c
-@@ -306,7 +306,8 @@ struct ssh_list *ssh_known_hosts_get_algorithms(ssh_session session)
-     int list_error = 0;
-     int rc;
- 
--    if (session->opts.knownhosts == NULL) {
-+    if (session->opts.knownhosts == NULL ||
-+        session->opts.global_knownhosts == NULL) {
-         if (ssh_options_apply(session) < 0) {
-             ssh_set_error(session,
-                           SSH_REQUEST_DENIED,
--- 
-2.19.1
-
diff --git a/SOURCES/libssh-0.8.5.tar.xz.asc b/SOURCES/libssh-0.8.5.tar.xz.asc
deleted file mode 100644
index 446b5b9..0000000
--- a/SOURCES/libssh-0.8.5.tar.xz.asc
+++ /dev/null
@@ -1,16 +0,0 @@
------BEGIN PGP SIGNATURE-----
-
-iQIzBAABCAAdFiEEjf9T4Y8qvI2PPJIjfuD8TcwBTj0FAlvW3ZEACgkQfuD8TcwB
-Tj0mPw/9HZty2xOzKekX8+cedyZbW2lAoG9YNVxgTvQ2+98+TBH6M8qr5EryuH/q
-mAFq/TJOrM3yccr1kJXFOm6QBw0xMTpWcosXjKmZxvJwW6iFEP33shVDkZGJWwmM
-bzr165NTdRMJiaBfk47j0e1H2U9MHyV7wKmb79+bFtMDhiJYmXR1Oxa1SjjeG42c
-XmrcH559kZ1mKmai6jKwTRUKGu3RLdWrXQIobCrdQM8FYrbSx5luZtDjdfXTRRtv
-K96alBYxuey1nsZVei1y2hJlLLLVqao997Q7iMI63+/IJpYTmEPciDnTDDu767X6
-rCXSuWbxcwk77zrt/dh7WJBOyLwh4aCFsSixBsONj4otwmFHNm/FAxV991ewcvQB
-NMHPh3DcYLfoY/aUzwf160SfZu56mdVnFPLOnPUw3ARcPdgJG4OzqP9Jmz4Us+dS
-ImZTduM62/+Af+LrODtRBRYJRSn38eBVVBYT01WsDSvvR2LaTn3gVAtY2m3Dr6wA
-6sdMmYbn2zM+MNFE1+qlsaKmF+WmyCrBKBojBB+wh5G+dStJ7KGzlXjxNQudvWeA
-VMlERLZYNBjSH1/XBH6VTnOl2xhExPv4eCUTVCXhlYUFEWjRunoxEed+b7r45iiu
-+nRT+OfQZ8RFOLkFYxhB8iQNZAZ6T46ALSxo3V8PVEPDHZWdPTU=
-=7iiz
------END PGP SIGNATURE-----
diff --git a/SOURCES/libssh-0.9.0-do-not-ignore-known-hosts-keys.patch b/SOURCES/libssh-0.9.0-do-not-ignore-known-hosts-keys.patch
new file mode 100644
index 0000000..c007677
--- /dev/null
+++ b/SOURCES/libssh-0.9.0-do-not-ignore-known-hosts-keys.patch
@@ -0,0 +1,1240 @@
+From b040856ccfde1a5d4c21791f46ca6ee00c21a47b Mon Sep 17 00:00:00 2001
+From: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
+Date: Tue, 2 Jul 2019 10:21:15 +0200
+Subject: [PATCH 1/6] knownhosts: Fix possible memory leak
+
+The memory allocated for host_port can leak if the global knownhosts
+file is unaccessible.
+
+Found by address sanitizer build in CI.
+
+Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
+Reviewed-by: Jakub Jelen <jjelen@redhat.com>
+(cherry picked from commit fe248414fec1e654e4ee1259927d68777dd870ae)
+---
+ src/knownhosts.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/src/knownhosts.c b/src/knownhosts.c
+index 8a4a8ba7..9383cc97 100644
+--- a/src/knownhosts.c
++++ b/src/knownhosts.c
+@@ -706,13 +706,15 @@ enum ssh_known_hosts_e ssh_session_has_known_hosts_entry(ssh_session session)
+         rc = ssh_known_hosts_read_entries(host_port,
+                                           session->opts.global_knownhosts,
+                                           &entry_list);
+-        SAFE_FREE(host_port);
+         if (rc != 0) {
++            SAFE_FREE(host_port);
+             ssh_list_free(entry_list);
+             return SSH_KNOWN_HOSTS_ERROR;
+         }
+     }
+ 
++    SAFE_FREE(host_port);
++
+     if (ssh_list_count(entry_list) == 0) {
+         ssh_list_free(entry_list);
+         return SSH_KNOWN_HOSTS_UNKNOWN;
+-- 
+2.21.0
+
+
+From 7ff0af75436ee6e549907dd563e968b92f7f8db2 Mon Sep 17 00:00:00 2001
+From: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
+Date: Fri, 28 Jun 2019 13:19:51 +0200
+Subject: [PATCH 2/6] tests: Check if known_hosts works with single
+ unaccessible file
+
+Make sure known hosts check works when local known_hosts file is
+unaccessible, but the host is present in global known_hosts file.
+
+Remove double return value check in previous existing test.
+
+Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
+Reviewed-by: Jakub Jelen <jjelen@redhat.com>
+(cherry picked from commit ad68de7271e6ccda261df4d9fc827321e7d90fd0)
+---
+ tests/unittests/torture_knownhosts_parsing.c | 19 +++++++++++--------
+ 1 file changed, 11 insertions(+), 8 deletions(-)
+
+diff --git a/tests/unittests/torture_knownhosts_parsing.c b/tests/unittests/torture_knownhosts_parsing.c
+index ac8d7f31..a087caef 100644
+--- a/tests/unittests/torture_knownhosts_parsing.c
++++ b/tests/unittests/torture_knownhosts_parsing.c
+@@ -384,22 +384,19 @@ static void torture_knownhosts_host_exists(void **state)
+ 
+     /* This makes sure the system's known_hosts are not used */
+     ssh_options_set(session, SSH_OPTIONS_GLOBAL_KNOWNHOSTS, "/dev/null");
+-
+     found = ssh_session_has_known_hosts_entry(session);
+     assert_int_equal(found, SSH_KNOWN_HOSTS_OK);
+-    assert_true(found == SSH_KNOWN_HOSTS_OK);
+ 
+     /* This makes sure the check will not fail when the system's known_hosts is
+      * not accessible*/
+     ssh_options_set(session, SSH_OPTIONS_GLOBAL_KNOWNHOSTS, "./unaccessible");
+-
+     found = ssh_session_has_known_hosts_entry(session);
+     assert_int_equal(found, SSH_KNOWN_HOSTS_OK);
+-    assert_true(found == SSH_KNOWN_HOSTS_OK);
+ 
++    /* This makes sure the check will fail for an unknown host */
+     ssh_options_set(session, SSH_OPTIONS_HOST, "wurstbrot");
+     found = ssh_session_has_known_hosts_entry(session);
+-    assert_true(found == SSH_KNOWN_HOSTS_UNKNOWN);
++    assert_int_equal(found, SSH_KNOWN_HOSTS_UNKNOWN);
+ 
+     ssh_free(session);
+ }
+@@ -414,17 +411,23 @@ static void torture_knownhosts_host_exists_global(void **state)
+     assert_non_null(session);
+ 
+     ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
++    ssh_options_set(session, SSH_OPTIONS_GLOBAL_KNOWNHOSTS, knownhosts_file);
++
+     /* This makes sure the user's known_hosts are not used */
+     ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, "/dev/null");
+-    ssh_options_set(session, SSH_OPTIONS_GLOBAL_KNOWNHOSTS, knownhosts_file);
++    found = ssh_session_has_known_hosts_entry(session);
++    assert_int_equal(found, SSH_KNOWN_HOSTS_OK);
+ 
++    /* This makes sure the check will not fail when the user's known_hosts is
++     * not accessible*/
++    ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, "./unaccessible");
+     found = ssh_session_has_known_hosts_entry(session);
+     assert_int_equal(found, SSH_KNOWN_HOSTS_OK);
+-    assert_true(found == SSH_KNOWN_HOSTS_OK);
+ 
++    /* This makes sure the check will fail for an unknown host */
+     ssh_options_set(session, SSH_OPTIONS_HOST, "wurstbrot");
+     found = ssh_session_has_known_hosts_entry(session);
+-    assert_true(found == SSH_KNOWN_HOSTS_UNKNOWN);
++    assert_int_equal(found, SSH_KNOWN_HOSTS_UNKNOWN);
+ 
+     ssh_free(session);
+ }
+-- 
+2.21.0
+
+
+From b9530cedbeb169762307096dfeb485ab94e09740 Mon Sep 17 00:00:00 2001
+From: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
+Date: Fri, 28 Jun 2019 13:27:34 +0200
+Subject: [PATCH 3/6] knownhosts: Read knownhosts file only if found
+
+Avoid trying to open the files if they are not accessible.  This was
+already treated as a non-error, but with this we save one function call.
+
+Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
+Reviewed-by: Jakub Jelen <jjelen@redhat.com>
+(cherry picked from commit e5a64a3d6b1b601cbaf207468a6658d1a4fa0031)
+---
+ src/knownhosts.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/knownhosts.c b/src/knownhosts.c
+index 9383cc97..8040a0c0 100644
+--- a/src/knownhosts.c
++++ b/src/knownhosts.c
+@@ -691,7 +691,7 @@ enum ssh_known_hosts_e ssh_session_has_known_hosts_entry(ssh_session session)
+         return SSH_KNOWN_HOSTS_ERROR;
+     }
+ 
+-    if (session->opts.knownhosts != NULL) {
++    if (known_hosts_found) {
+         rc = ssh_known_hosts_read_entries(host_port,
+                                           session->opts.knownhosts,
+                                           &entry_list);
+@@ -702,7 +702,7 @@ enum ssh_known_hosts_e ssh_session_has_known_hosts_entry(ssh_session session)
+         }
+     }
+ 
+-    if (session->opts.global_knownhosts != NULL) {
++    if (global_known_hosts_found) {
+         rc = ssh_known_hosts_read_entries(host_port,
+                                           session->opts.global_knownhosts,
+                                           &entry_list);
+-- 
+2.21.0
+
+
+From aaa978ad06ebdeff88a39b9a894696254263162c Mon Sep 17 00:00:00 2001
+From: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
+Date: Fri, 28 Jun 2019 22:35:38 +0200
+Subject: [PATCH 4/6] token: Added function to remove duplicates
+
+Added a function to remove duplicates from lists.  This function is used
+in a new provided function to append lists removing duplicates.
+
+Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
+Reviewed-by: Jakub Jelen <jjelen@redhat.com>
+(cherry picked from commit 548753b3389518ebce98a7ddbf0640db3ad72de8)
+---
+ include/libssh/token.h           |   6 +-
+ src/token.c                      | 152 ++++++++++++++++++++++++++++++-
+ tests/unittests/torture_tokens.c | 122 +++++++++++++++++++++++++
+ 3 files changed, 278 insertions(+), 2 deletions(-)
+
+diff --git a/include/libssh/token.h b/include/libssh/token.h
+index 7b244189..9896fb06 100644
+--- a/include/libssh/token.h
++++ b/include/libssh/token.h
+@@ -38,7 +38,11 @@ void ssh_tokens_free(struct ssh_tokens_st *tokens);
+ char *ssh_find_matching(const char *available_d,
+                         const char *preferred_d);
+ 
+-
+ char *ssh_find_all_matching(const char *available_d,
+                             const char *preferred_d);
++
++char *ssh_remove_duplicates(const char *list);
++
++char *ssh_append_without_duplicates(const char *list,
++                                    const char *appended_list);
+ #endif /* TOKEN_H_ */
+diff --git a/src/token.c b/src/token.c
+index aee235ac..0924d3bd 100644
+--- a/src/token.c
++++ b/src/token.c
+@@ -26,6 +26,7 @@
+ 
+ #include <stdio.h>
+ #include <string.h>
++#include <stdbool.h>
+ 
+ #include "libssh/priv.h"
+ #include "libssh/token.h"
+@@ -175,7 +176,7 @@ char *ssh_find_matching(const char *available_list,
+ 
+     for (i = 0; p_tok->tokens[i]; i++) {
+         for (j = 0; a_tok->tokens[j]; j++) {
+-            if (strcmp(a_tok->tokens[j], p_tok->tokens[i]) == 0){
++            if (strcmp(a_tok->tokens[j], p_tok->tokens[i]) == 0) {
+                 ret = strdup(a_tok->tokens[j]);
+                 goto out;
+             }
+@@ -260,3 +261,152 @@ out:
+     ssh_tokens_free(p_tok);
+     return ret;
+ }
++
++/**
++ * @internal
++ *
++ * @brief Given a string containing a list of elements, remove all duplicates
++ * and return in a newly allocated string.
++ *
++ * @param[in] list  The list to be freed of duplicates
++ *
++ * @return  A newly allocated copy of the string free of duplicates; NULL in
++ * case of error.
++ */
++char *ssh_remove_duplicates(const char *list)
++{
++    struct ssh_tokens_st *tok = NULL;
++
++    size_t i, j, num_tokens, max_len;
++    char *ret = NULL;
++    bool *should_copy = NULL, need_comma = false;
++
++    if (list == NULL) {
++        return NULL;
++    }
++
++    /* The maximum number of tokens is the size of the list */
++    max_len = strlen(list);
++    if (max_len == 0) {
++        return NULL;
++    }
++
++    /* Add space for ending '\0' */
++    max_len++;
++
++    tok = ssh_tokenize(list, ',');
++    if ((tok == NULL) || (tok->tokens == NULL) || (tok->tokens[0] == NULL)) {
++        goto out;
++    }
++
++    should_copy = calloc(1, max_len);
++    if (should_copy == NULL) {
++        goto out;
++    }
++
++    if (strlen(tok->tokens[0]) > 0) {
++        should_copy[0] = true;
++    }
++
++    for (i = 1; tok->tokens[i]; i++) {
++        for (j = 0; j < i; j++) {
++            if (strcmp(tok->tokens[i], tok->tokens[j]) == 0) {
++                /* Found a duplicate; do not copy */
++                should_copy[i] = false;
++                break;
++            }
++        }
++
++        /* No matching token before */
++        if (j == i) {
++            /* Only copy if it is not an empty string */
++            if (strlen(tok->tokens[i]) > 0) {
++                should_copy[i] = true;
++            } else {
++                should_copy[i] = false;
++            }
++        }
++    }
++
++    num_tokens = i;
++
++    ret = calloc(1, max_len);
++    if (ret == NULL) {
++        goto out;
++    }
++
++    for (i = 0; i < num_tokens; i++) {
++        if (should_copy[i]) {
++            if (need_comma) {
++                strncat(ret, ",", (max_len - strlen(ret) - 1));
++            }
++            strncat(ret, tok->tokens[i], (max_len - strlen(ret) - 1));
++            need_comma = true;
++        }
++    }
++
++    /* If no comma is needed, nothing was copied */
++    if (!need_comma) {
++        SAFE_FREE(ret);
++    }
++
++out:
++    SAFE_FREE(should_copy);
++    ssh_tokens_free(tok);
++    return ret;
++}
++
++/**
++ * @internal
++ *
++ * @brief Given two strings containing lists of tokens, return a newly
++ * allocated string containing all the elements of the first list appended with
++ * all the elements of the second list, without duplicates. The order of the
++ * elements will be preserved.
++ *
++ * @param[in] list             The first list
++ * @param[in] appended_list    The list to be appended
++ *
++ * @return  A newly allocated copy list containing all the elements of the
++ * kept_list appended with the elements of the appended_list without duplicates;
++ * NULL in case of error.
++ */
++char *ssh_append_without_duplicates(const char *list,
++                                    const char *appended_list)
++{
++    size_t concat_len = 0;
++    char *ret = NULL, *concat = NULL;
++
++    if (list != NULL) {
++        concat_len = strlen(list);
++    }
++
++    if (appended_list != NULL) {
++        concat_len += strlen(appended_list);
++    }
++
++    if (concat_len == 0) {
++        return NULL;
++    }
++
++    /* Add room for ending '\0' and for middle ',' */
++    concat_len += 2;
++    concat = calloc(1, concat_len);
++    if (concat == NULL) {
++        return NULL;
++    }
++
++    if (list != NULL) {
++        strcpy(concat, list);
++        strncat(concat, ",", concat_len - strlen(concat) - 1);
++    }
++    if (appended_list != NULL) {
++        strncat(concat, appended_list, concat_len - strlen(concat) - 1);
++    }
++
++    ret = ssh_remove_duplicates(concat);
++
++    SAFE_FREE(concat);
++
++    return ret;
++}
+diff --git a/tests/unittests/torture_tokens.c b/tests/unittests/torture_tokens.c
+index e192842f..6b52b847 100644
+--- a/tests/unittests/torture_tokens.c
++++ b/tests/unittests/torture_tokens.c
+@@ -146,6 +146,126 @@ static void torture_tokens_sanity(UNUSED_PARAM(void **state))
+     tokenize_compare_expected(",", single_colon, 1);
+ }
+ 
++static void torture_remove_duplicate(UNUSED_PARAM(void **state))
++{
++
++    const char *simple[] = {"a,a,b,b,c,c",
++                            "a,b,c,a,b,c",
++                            "a,b,c,c,b,a",
++                            "a,a,,b,b,,c,c",
++                            ",a,a,b,b,c,c",
++                            "a,a,b,b,c,c,"};
++    const char *empty[] = {"",
++                           ",,,,,,,,,",
++                           NULL};
++    char *ret = NULL;
++    int i;
++
++    for (i = 0; i < 6; i++) {
++        ret = ssh_remove_duplicates(simple[i]);
++        assert_non_null(ret);
++        assert_string_equal("a,b,c", ret);
++        printf("simple[%d] resulted in '%s'\n", i, ret);
++        SAFE_FREE(ret);
++    }
++
++    for (i = 0; i < 3; i++) {
++        ret = ssh_remove_duplicates(empty[i]);
++        if (ret != NULL) {
++            printf("empty[%d] resulted in '%s'\n", i, ret);
++        }
++        assert_null(ret);
++    }
++
++    ret = ssh_remove_duplicates("a");
++    assert_non_null(ret);
++    assert_string_equal("a", ret);
++    SAFE_FREE(ret);
++}
++
++static void torture_append_without_duplicate(UNUSED_PARAM(void **state))
++{
++    const char *s1[] = {"a,a,b,b,c,c",
++                        "a,b,c,a,b,c",
++                        "a,b,c,c,b,a",
++                        "a,a,,b,b,,c,c",
++                        ",a,a,b,b,c,c",
++                        "a,a,b,b,c,c,"};
++    const char *s2[] = {"a,a,b,b,c,c,d,d",
++                        "a,b,c,d,a,b,c,d",
++                        "a,b,c,d,d,c,b,a",
++                        "a,a,,b,b,,c,c,,d,d",
++                        ",a,a,b,b,c,c,d,d",
++                        "a,a,b,b,c,c,d,d,",
++                        "d"};
++    const char *empty[] = {"",
++                           ",,,,,,,,,",
++                           NULL,
++                           NULL};
++    char *ret = NULL;
++    int i, j;
++
++    ret = ssh_append_without_duplicates("a", "a");
++    assert_non_null(ret);
++    assert_string_equal("a", ret);
++    SAFE_FREE(ret);
++
++    ret = ssh_append_without_duplicates("a", "b");
++    assert_non_null(ret);
++    assert_string_equal("a,b", ret);
++    SAFE_FREE(ret);
++
++    ret = ssh_append_without_duplicates("a", NULL);
++    assert_non_null(ret);
++    assert_string_equal("a", ret);
++    SAFE_FREE(ret);
++
++    ret = ssh_append_without_duplicates(NULL, "b");
++    assert_non_null(ret);
++    assert_string_equal("b", ret);
++    SAFE_FREE(ret);
++
++    for (i = 0; i < 6; i++) {
++        for (j = 0; j < 7; j++) {
++            ret = ssh_append_without_duplicates(s1[i], s2[j]);
++            assert_non_null(ret);
++            printf("s1[%d] + s2[%d] resulted in '%s'\n", i, j, ret);
++            assert_string_equal("a,b,c,d", ret);
++            SAFE_FREE(ret);
++        }
++    }
++
++    for (i = 0; i < 6; i++) {
++        for (j = 0; j < 3; j++) {
++            ret = ssh_append_without_duplicates(s1[i], empty[j]);
++            assert_non_null(ret);
++            printf("s1[%d] + empty[%d] resulted in '%s'\n", i, j, ret);
++            assert_string_equal("a,b,c", ret);
++            SAFE_FREE(ret);
++        }
++    }
++
++    for (i = 0; i < 3; i++) {
++        for (j = 0; j < 6; j++) {
++            ret = ssh_append_without_duplicates(empty[i], s1[j]);
++            assert_non_null(ret);
++            printf("empty[%d] + s1[%d] resulted in '%s'\n", i, j, ret);
++            assert_string_equal("a,b,c", ret);
++            SAFE_FREE(ret);
++        }
++    }
++    for (i = 0; i < 4; i++) {
++        for (j = 0; j < 4; j++) {
++            ret = ssh_append_without_duplicates(empty[i], empty[j]);
++            if (ret != NULL) {
++                printf("empty[%d] + empty[%d] resulted in '%s'\n", i, j, ret);
++            }
++            assert_null(ret);
++        }
++    }
++}
++
++
+ int torture_run_tests(void)
+ {
+     int rc;
+@@ -153,6 +273,8 @@ int torture_run_tests(void)
+         cmocka_unit_test(torture_tokens_sanity),
+         cmocka_unit_test(torture_find_matching),
+         cmocka_unit_test(torture_find_all_matching),
++        cmocka_unit_test(torture_remove_duplicate),
++        cmocka_unit_test(torture_append_without_duplicate),
+     };
+ 
+     ssh_init();
+-- 
+2.21.0
+
+
+From fa3caa61fdb39269cd78c4919df515b71991d231 Mon Sep 17 00:00:00 2001
+From: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
+Date: Tue, 2 Jul 2019 13:48:17 +0200
+Subject: [PATCH 5/6] knownhosts: Introduced
+ ssh_known_hosts_get_algorithms_names()
+
+The added internal function obtain a newly allocated string containing a
+list of the signature types that can be generated by the keys present in
+the known_hosts files, separated by commas.
+
+Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
+Reviewed-by: Jakub Jelen <jjelen@redhat.com>
+(cherry picked from commit 65a38759ca872e8bec0158ab3676e74b6afd336f)
+---
+ include/libssh/knownhosts.h                  |   1 +
+ src/knownhosts.c                             | 141 +++++++++++++++++++
+ tests/unittests/torture_knownhosts_parsing.c |  28 ++++
+ 3 files changed, 170 insertions(+)
+
+diff --git a/include/libssh/knownhosts.h b/include/libssh/knownhosts.h
+index dcaa6c24..44e434c0 100644
+--- a/include/libssh/knownhosts.h
++++ b/include/libssh/knownhosts.h
+@@ -23,6 +23,7 @@
+ #define SSH_KNOWNHOSTS_H_
+ 
+ struct ssh_list *ssh_known_hosts_get_algorithms(ssh_session session);
++char *ssh_known_hosts_get_algorithms_names(ssh_session session);
+ enum ssh_known_hosts_e
+ ssh_session_get_known_hosts_entry_file(ssh_session session,
+                                        const char *filename,
+diff --git a/src/knownhosts.c b/src/knownhosts.c
+index 8040a0c0..cf9d8a6b 100644
+--- a/src/knownhosts.c
++++ b/src/knownhosts.c
+@@ -42,6 +42,7 @@
+ #include "libssh/pki.h"
+ #include "libssh/dh.h"
+ #include "libssh/knownhosts.h"
++#include "libssh/token.h"
+ 
+ /**
+  * @addtogroup libssh_session
+@@ -451,6 +452,146 @@ error:
+     return NULL;
+ }
+ 
++/**
++ * @internal
++ *
++ * @brief   Returns a static string containing a list of the signature types the
++ * given key type can generate.
++ *
++ * @returns A static cstring containing the signature types the key is able to
++ * generate separated by commas; NULL in case of error
++ */
++static const char *ssh_known_host_sigs_from_hostkey_type(enum ssh_keytypes_e type)
++{
++    switch (type) {
++    case SSH_KEYTYPE_RSA:
++        return "rsa-sha2-512,rsa-sha2-256,ssh-rsa";
++    case SSH_KEYTYPE_ED25519:
++        return "ssh-ed25519";
++#ifdef HAVE_DSA
++    case SSH_KEYTYPE_DSS:
++        return "ssh-dss";
++#endif
++#ifdef HAVE_ECDH
++    case SSH_KEYTYPE_ECDSA_P256:
++        return "ecdsa-sha2-nistp256";
++    case SSH_KEYTYPE_ECDSA_P384:
++        return "ecdsa-sha2-nistp384";
++    case SSH_KEYTYPE_ECDSA_P521:
++        return "ecdsa-sha2-nistp521";
++#endif
++    case SSH_KEYTYPE_UNKNOWN:
++    default:
++        SSH_LOG(SSH_LOG_WARN, "The given type %d is not a base private key type "
++                "or is unsupported", type);
++        return NULL;
++    }
++}
++
++/**
++ * @internal
++ * @brief Get the host keys algorithms identifiers from the known_hosts files
++ *
++ * This expands the signatures types that can be generated from the keys types
++ * present in the known_hosts files
++ *
++ * @param[in]  session  The ssh session to use.
++ *
++ * @return A newly allocated cstring containing a list of signature algorithms
++ * that can be generated by the host using the keys listed in the known_hosts
++ * files, NULL on error.
++ */
++char *ssh_known_hosts_get_algorithms_names(ssh_session session)
++{
++    char methods_buffer[256 + 1] = {0};
++    struct ssh_list *entry_list = NULL;
++    struct ssh_iterator *it = NULL;
++    char *host_port = NULL;
++    size_t count;
++    bool needcomma = false;
++    char *names;
++
++    int rc;
++
++    if (session->opts.knownhosts == NULL ||
++        session->opts.global_knownhosts == NULL) {
++        if (ssh_options_apply(session) < 0) {
++            ssh_set_error(session,
++                          SSH_REQUEST_DENIED,
++                          "Can't find a known_hosts file");
++
++            return NULL;
++        }
++    }
++
++    host_port = ssh_session_get_host_port(session);
++    if (host_port == NULL) {
++        return NULL;
++    }
++
++    rc = ssh_known_hosts_read_entries(host_port,
++                                      session->opts.knownhosts,
++                                      &entry_list);
++    if (rc != 0) {
++        SAFE_FREE(host_port);
++        ssh_list_free(entry_list);
++        return NULL;
++    }
++
++    rc = ssh_known_hosts_read_entries(host_port,
++                                      session->opts.global_knownhosts,
++                                      &entry_list);
++    SAFE_FREE(host_port);
++    if (rc != 0) {
++        ssh_list_free(entry_list);
++        return NULL;
++    }
++
++    if (entry_list == NULL) {
++        return NULL;
++    }
++
++    count = ssh_list_count(entry_list);
++    if (count == 0) {
++        ssh_list_free(entry_list);
++        return NULL;
++    }
++
++    for (it = ssh_list_get_iterator(entry_list);
++         it != NULL;
++         it = ssh_list_get_iterator(entry_list))
++    {
++        struct ssh_knownhosts_entry *entry = NULL;
++        const char *algo = NULL;
++
++        entry = ssh_iterator_value(struct ssh_knownhosts_entry *, it);
++        algo = ssh_known_host_sigs_from_hostkey_type(entry->publickey->type);
++        if (algo == NULL) {
++            continue;
++        }
++
++        if (needcomma) {
++            strncat(methods_buffer,
++                    ",",
++                    sizeof(methods_buffer) - strlen(methods_buffer) - 1);
++        }
++
++        strncat(methods_buffer,
++                algo,
++                sizeof(methods_buffer) - strlen(methods_buffer) - 1);
++        needcomma = true;
++
++        ssh_knownhosts_entry_free(entry);
++        ssh_list_remove(entry_list, it);
++    }
++
++    ssh_list_free(entry_list);
++
++    names = ssh_remove_duplicates(methods_buffer);
++
++    return names;
++}
++
+ /**
+  * @brief Parse a line from a known_hosts entry into a structure
+  *
+diff --git a/tests/unittests/torture_knownhosts_parsing.c b/tests/unittests/torture_knownhosts_parsing.c
+index a087caef..6952e858 100644
+--- a/tests/unittests/torture_knownhosts_parsing.c
++++ b/tests/unittests/torture_knownhosts_parsing.c
+@@ -369,6 +369,31 @@ static void torture_knownhosts_read_file(void **state)
+     ssh_list_free(entry_list);
+ }
+ 
++static void torture_knownhosts_get_algorithms_names(void **state)
++{
++    const char *knownhosts_file = *state;
++    ssh_session session;
++    const char *expect = "ssh-ed25519,rsa-sha2-512,rsa-sha2-256,ssh-rsa";
++    char *names = NULL;
++    bool process_config = false;
++
++    session = ssh_new();
++    assert_non_null(session);
++
++    /* This makes sure the global configuration file is not processed */
++    ssh_options_set(session, SSH_OPTIONS_PROCESS_CONFIG, &process_config);
++
++    ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
++    ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, knownhosts_file);
++
++    names = ssh_known_hosts_get_algorithms_names(session);
++    assert_non_null(names);
++    assert_string_equal(names, expect);
++
++    SAFE_FREE(names);
++    ssh_free(session);
++}
++
+ #ifndef _WIN32 /* There is no /dev/null on Windows */
+ static void torture_knownhosts_host_exists(void **state)
+ {
+@@ -510,6 +535,9 @@ int torture_run_tests(void) {
+         cmocka_unit_test_setup_teardown(torture_knownhosts_read_file,
+                                         setup_knownhosts_file_duplicate,
+                                         teardown_knownhosts_file),
++        cmocka_unit_test_setup_teardown(torture_knownhosts_get_algorithms_names,
++                                        setup_knownhosts_file,
++                                        teardown_knownhosts_file),
+ #ifndef _WIN32
+         cmocka_unit_test_setup_teardown(torture_knownhosts_host_exists,
+                                         setup_knownhosts_file,
+-- 
+2.21.0
+
+
+From 1fd68ec732214a12ba3f59ca23f80463411e22dd Mon Sep 17 00:00:00 2001
+From: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
+Date: Mon, 1 Jul 2019 19:39:07 +0200
+Subject: [PATCH 6/6] kex: Do not ignore keys in known_hosts files
+
+Previously, if the SSH_OPTIONS_HOSTKEYS option was set by any mean,
+including the client configuration file, the keys in known_hosts files
+wouldn't be considered before advertising the list of wanted host keys.
+
+This could result in the client requesting the server to provide a
+signature using a key not present in the known_hosts files (e.g. when
+the first wanted algorithm in SSH_OPTIONS_HOSTKEYS is not present in the
+known_hosts files), causing a host key mismatch and possible key
+rejection.
+
+Now, the keys present in the known_hosts files are prioritized over the
+other wanted keys.  This do not change the fact that only keys of types
+present in the list set in SSH_OPTIONS_HOSTKEYS will be accepted and
+prioritized following the order defined by such list.
+
+The new wanted list of hostkeys is given by:
+ - The keys present in known_hosts files, ordered by preference defined
+   in SSH_OPTIONS_HOSTKEYS.  If the option is not set, a default order
+   of preference is used.
+ - The other keys present in the same option are appended without adding
+   duplicates.  If the option is not set, the default list of keys is
+   used.
+
+Fixes: T156
+
+Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
+Reviewed-by: Jakub Jelen <jjelen@redhat.com>
+(cherry picked from commit f18a7cc17e399ae7bc92f707da3a676c52fd948e)
+---
+ src/kex.c                                    | 165 +++++++++----------
+ tests/unittests/torture_knownhosts_parsing.c | 148 ++++++++++++++++-
+ 2 files changed, 223 insertions(+), 90 deletions(-)
+
+diff --git a/src/kex.c b/src/kex.c
+index 6ea5e8ba..0d4cad6d 100644
+--- a/src/kex.c
++++ b/src/kex.c
+@@ -561,103 +561,94 @@ void ssh_list_kex(struct ssh_kex_struct *kex) {
+ 
+ /**
+  * @internal
++ *
+  * @brief selects the hostkey mechanisms to be chosen for the key exchange,
+- * as some hostkey mechanisms may be present in known_hosts file and preferred
++ * as some hostkey mechanisms may be present in known_hosts files.
++ *
+  * @returns a cstring containing a comma-separated list of hostkey methods.
+  *          NULL if no method matches
+  */
+ char *ssh_client_select_hostkeys(ssh_session session)
+ {
+-    char methods_buffer[128]={0};
+-    char tail_buffer[128]={0};
++    const char *wanted = NULL;
++    char *wanted_without_certs = NULL;
++    char *known_hosts_algorithms = NULL;
++    char *known_hosts_ordered = NULL;
+     char *new_hostkeys = NULL;
+-    static const char *preferred_hostkeys[] = {
+-        "ssh-ed25519",
+-        "ecdsa-sha2-nistp521",
+-        "ecdsa-sha2-nistp384",
+-        "ecdsa-sha2-nistp256",
+-        "rsa-sha2-512",
+-        "rsa-sha2-256",
+-        "ssh-rsa",
+-#ifdef HAVE_DSA
+-        "ssh-dss",
+-#endif
+-        NULL
+-    };
+-    struct ssh_list *algo_list = NULL;
+-    struct ssh_iterator *it = NULL;
+-    size_t algo_count;
+-    int needcomma = 0;
+-    size_t i, len;
+-
+-    algo_list = ssh_known_hosts_get_algorithms(session);
+-    if (algo_list == NULL) {
+-        return NULL;
++    char *fips_hostkeys = NULL;
++
++    wanted = session->opts.wanted_methods[SSH_HOSTKEYS];
++    if (wanted == NULL) {
++        if (ssh_fips_mode()) {
++            wanted = ssh_kex_get_fips_methods(SSH_HOSTKEYS);
++        } else {
++            wanted = ssh_kex_get_default_methods(SSH_HOSTKEYS);
++        }
+     }
+ 
+-    algo_count = ssh_list_count(algo_list);
+-    if (algo_count == 0) {
+-        ssh_list_free(algo_list);
++    /* This removes the certificate types, unsupported for now */
++    wanted_without_certs = ssh_find_all_matching(HOSTKEYS, wanted);
++    if (wanted_without_certs == NULL) {
++        SSH_LOG(SSH_LOG_WARNING,
++                "List of allowed host key algorithms is empty or contains only "
++                "unsupported algorithms");
+         return NULL;
+     }
+ 
+-    for (i = 0; preferred_hostkeys[i] != NULL; ++i) {
+-        bool found = false;
+-        /* This is a signature type: We list also the SHA2 extensions */
+-        enum ssh_keytypes_e base_preferred =
+-            ssh_key_type_from_signature_name(preferred_hostkeys[i]);
+-
+-        for (it = ssh_list_get_iterator(algo_list);
+-             it != NULL;
+-             it = it->next) {
+-            const char *algo = ssh_iterator_value(const char *, it);
+-            /* This is always key type so we do not have to care for the
+-             * SHA2 extension */
+-            enum ssh_keytypes_e base_algo = ssh_key_type_from_name(algo);
+-
+-            if (base_preferred == base_algo) {
+-                /* Matching the keys already verified it is a known type */
+-                if (needcomma) {
+-                    strncat(methods_buffer,
+-                            ",",
+-                            sizeof(methods_buffer) - strlen(methods_buffer) - 1);
+-                }
+-                strncat(methods_buffer,
+-                        preferred_hostkeys[i],
+-                        sizeof(methods_buffer) - strlen(methods_buffer) - 1);
+-                needcomma = 1;
+-                found = true;
+-            }
+-        }
+-        /* Collect the rest of the algorithms in other buffer, that will
+-         * follow the preferred buffer. This will signalize all the algorithms
+-         * we are willing to accept.
+-         */
+-        if (!found) {
+-            snprintf(tail_buffer + strlen(tail_buffer),
+-                     sizeof(tail_buffer) - strlen(tail_buffer),
+-                     ",%s", preferred_hostkeys[i]);
+-        }
++    SSH_LOG(SSH_LOG_DEBUG,
++            "Order of wanted host keys: \"%s\"",
++            wanted_without_certs);
++
++    known_hosts_algorithms = ssh_known_hosts_get_algorithms_names(session);
++    if (known_hosts_algorithms == NULL) {
++        SSH_LOG(SSH_LOG_DEBUG,
++                "No key found in known_hosts; "
++                "changing host key method to \"%s\"",
++                wanted_without_certs);
++
++        return wanted_without_certs;
+     }
+-    ssh_list_free(algo_list);
+ 
+-    if (strlen(methods_buffer) == 0) {
++    SSH_LOG(SSH_LOG_DEBUG,
++            "Algorithms found in known_hosts files: \"%s\"",
++            known_hosts_algorithms);
++
++    /* Filter and order the keys from known_hosts according to wanted list */
++    known_hosts_ordered = ssh_find_all_matching(known_hosts_algorithms,
++                                                wanted_without_certs);
++    SAFE_FREE(known_hosts_algorithms);
++    if (known_hosts_ordered == NULL) {
+         SSH_LOG(SSH_LOG_DEBUG,
+-                "No supported kex method for existing key in known_hosts file");
+-        return NULL;
++                "No key found in known_hosts is allowed; "
++                "changing host key method to \"%s\"",
++                wanted_without_certs);
++
++        return wanted_without_certs;
+     }
+ 
+-    /* Append the supported list to the preferred.
+-     * The length is maximum 128 + 128 + 1, which will not overflow
+-     */
+-    len = strlen(methods_buffer) + strlen(tail_buffer) + 1;
+-    new_hostkeys = malloc(len);
++    /* Append the other supported keys after the preferred ones
++     * This function tolerates NULL pointers in parameters */
++    new_hostkeys = ssh_append_without_duplicates(known_hosts_ordered,
++                                                 wanted_without_certs);
++    SAFE_FREE(known_hosts_ordered);
++    SAFE_FREE(wanted_without_certs);
+     if (new_hostkeys == NULL) {
+         ssh_set_error_oom(session);
+         return NULL;
+     }
+-    snprintf(new_hostkeys, len,
+-             "%s%s", methods_buffer, tail_buffer);
++
++    if (ssh_fips_mode()) {
++        /* Filter out algorithms not allowed in FIPS mode */
++        fips_hostkeys = ssh_keep_fips_algos(SSH_HOSTKEYS, new_hostkeys);
++        SAFE_FREE(new_hostkeys);
++        if (fips_hostkeys == NULL) {
++            SSH_LOG(SSH_LOG_WARNING,
++                    "None of the wanted host keys or keys in known_hosts files "
++                    "is allowed in FIPS mode.");
++            return NULL;
++        }
++        new_hostkeys = fips_hostkeys;
++    }
+ 
+     SSH_LOG(SSH_LOG_DEBUG,
+             "Changing host key method to \"%s\"",
+@@ -672,7 +663,7 @@ char *ssh_client_select_hostkeys(ssh_session session)
+  */
+ int ssh_set_client_kex(ssh_session session)
+ {
+-    struct ssh_kex_struct *client= &session->next_crypto->client_kex;
++    struct ssh_kex_struct *client = &session->next_crypto->client_kex;
+     const char *wanted;
+     char *kex = NULL;
+     char *kex_tmp = NULL;
+@@ -687,14 +678,22 @@ int ssh_set_client_kex(ssh_session session)
+     }
+ 
+     memset(client->methods, 0, KEX_METHODS_SIZE * sizeof(char **));
+-    /* first check if we have specific host key methods */
+-    if (session->opts.wanted_methods[SSH_HOSTKEYS] == NULL) {
+-    	/* Only if no override */
+-    	session->opts.wanted_methods[SSH_HOSTKEYS] =
+-            ssh_client_select_hostkeys(session);
+-    }
+ 
++    /* Set the list of allowed algorithms in order of preference, if it hadn't
++     * been set yet. */
+     for (i = 0; i < KEX_METHODS_SIZE; i++) {
++        if (i == SSH_HOSTKEYS) {
++            /* Set the hostkeys in the following order:
++             * - First: keys present in known_hosts files ordered by preference
++             * - Next: other wanted algorithms ordered by preference */
++            client->methods[i] = ssh_client_select_hostkeys(session);
++            if (client->methods[i] == NULL) {
++                ssh_set_error_oom(session);
++                return SSH_ERROR;
++            }
++            continue;
++        }
++
+         wanted = session->opts.wanted_methods[i];
+         if (wanted == NULL) {
+             if (ssh_fips_mode()) {
+diff --git a/tests/unittests/torture_knownhosts_parsing.c b/tests/unittests/torture_knownhosts_parsing.c
+index 6952e858..1c2ccc10 100644
+--- a/tests/unittests/torture_knownhosts_parsing.c
++++ b/tests/unittests/torture_knownhosts_parsing.c
+@@ -28,6 +28,8 @@
+ 
+ #define TMP_FILE_NAME "/tmp/known_hosts_XXXXXX"
+ 
++const char template[] = "temp_dir_XXXXXX";
++
+ static int setup_knownhosts_file(void **state)
+ {
+     char *tmp_file = NULL;
+@@ -394,6 +396,115 @@ static void torture_knownhosts_get_algorithms_names(void **state)
+     ssh_free(session);
+ }
+ 
++static void torture_knownhosts_algorithms_wanted(void **state)
++{
++    const char *knownhosts_file = *state;
++    char *algo_list = NULL;
++    ssh_session session;
++    bool process_config = false;
++    const char *wanted = "ecdsa-sha2-nistp384,ecdsa-sha2-nistp256,"
++                         "rsa-sha2-256,ecdsa-sha2-nistp521";
++    const char *expect = "rsa-sha2-256,ecdsa-sha2-nistp384,"
++                         "ecdsa-sha2-nistp256,ecdsa-sha2-nistp521";
++    int verbose = 4;
++
++    session = ssh_new();
++    assert_non_null(session);
++
++    ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbose);
++
++    /* This makes sure the global configuration file is not processed */
++    ssh_options_set(session, SSH_OPTIONS_PROCESS_CONFIG, &process_config);
++
++    /* Set the wanted list of hostkeys, ordered by preference */
++    ssh_options_set(session, SSH_OPTIONS_HOSTKEYS, wanted);
++
++    ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
++    ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, knownhosts_file);
++
++    algo_list = ssh_client_select_hostkeys(session);
++    assert_non_null(algo_list);
++    assert_string_equal(algo_list, expect);
++    free(algo_list);
++
++    ssh_free(session);
++}
++
++static void torture_knownhosts_algorithms_negative(UNUSED_PARAM(void **state))
++{
++    const char *wanted = NULL;
++    const char *expect = NULL;
++
++    char *algo_list = NULL;
++
++    char *cwd = NULL;
++    char *tmp_dir = NULL;
++
++    bool process_config = false;
++    int verbose = 4;
++    int rc = 0;
++
++    ssh_session session;
++    /* Create temporary directory */
++    cwd = torture_get_current_working_dir();
++    assert_non_null(cwd);
++
++    tmp_dir = torture_make_temp_dir(template);
++    assert_non_null(tmp_dir);
++
++    rc = torture_change_dir(tmp_dir);
++    assert_int_equal(rc, 0);
++
++    session = ssh_new();
++    assert_non_null(session);
++
++    ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbose);
++    ssh_options_set(session, SSH_OPTIONS_PROCESS_CONFIG, &process_config);
++    ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
++
++    /* Test with unknown key type in known_hosts */
++    wanted = "rsa-sha2-256";
++    ssh_options_set(session, SSH_OPTIONS_HOSTKEYS, wanted);
++    torture_write_file("unknown_key_type", "localhost unknown AAAABBBBCCCC");
++    ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, "unknown_key_type");
++    algo_list = ssh_client_select_hostkeys(session);
++    assert_non_null(algo_list);
++    assert_string_equal(algo_list, wanted);
++    SAFE_FREE(algo_list);
++
++    /* Test with unsupported, but existing types */
++    wanted = "rsa-sha2-256-cert-v01@openssh.com,"
++             "rsa-sha2-512-cert-v01@openssh.com";
++    ssh_options_set(session, SSH_OPTIONS_HOSTKEYS, wanted);
++    algo_list = ssh_client_select_hostkeys(session);
++    assert_null(algo_list);
++
++    /* In FIPS mode, test filtering keys not allowed */
++    if (ssh_fips_mode()) {
++        wanted = "ssh-ed25519,rsa-sha2-256,ssh-rsa";
++        expect = "rsa-sha2-256";
++        ssh_options_set(session, SSH_OPTIONS_HOSTKEYS, wanted);
++        torture_write_file("no_fips", LOCALHOST_DEFAULT_ED25519);
++        ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, "no_fips");
++        algo_list = ssh_client_select_hostkeys(session);
++        assert_non_null(algo_list);
++        assert_string_equal(algo_list, expect);
++        SAFE_FREE(algo_list);
++    }
++
++    ssh_free(session);
++
++    /* Teardown */
++    rc = torture_change_dir(cwd);
++    assert_int_equal(rc, 0);
++
++    rc = torture_rmdirs(tmp_dir);
++    assert_int_equal(rc, 0);
++
++    SAFE_FREE(tmp_dir);
++    SAFE_FREE(cwd);
++}
++
+ #ifndef _WIN32 /* There is no /dev/null on Windows */
+ static void torture_knownhosts_host_exists(void **state)
+ {
+@@ -457,12 +568,12 @@ static void torture_knownhosts_host_exists_global(void **state)
+     ssh_free(session);
+ }
+ 
+-static void
+-torture_knownhosts_algorithms(void **state)
++static void torture_knownhosts_algorithms(void **state)
+ {
+     const char *knownhosts_file = *state;
+     char *algo_list = NULL;
+     ssh_session session;
++    bool process_config = false;
+     const char *expect = "ssh-ed25519,rsa-sha2-512,rsa-sha2-256,ssh-rsa,"
+                          "ecdsa-sha2-nistp521,ecdsa-sha2-nistp384,"
+                          "ecdsa-sha2-nistp256"
+@@ -470,10 +581,15 @@ torture_knownhosts_algorithms(void **state)
+                          ",ssh-dss"
+ #endif
+     ;
++    const char *expect_fips = "rsa-sha2-512,rsa-sha2-256,ecdsa-sha2-nistp521,"
++                              "ecdsa-sha2-nistp384,ecdsa-sha2-nistp256";
+ 
+     session = ssh_new();
+     assert_non_null(session);
+ 
++    /* This makes sure the global configuration file is not processed */
++    ssh_options_set(session, SSH_OPTIONS_PROCESS_CONFIG, &process_config);
++
+     ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
+     ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, knownhosts_file);
+     /* This makes sure the system's known_hosts are not used */
+@@ -481,18 +597,22 @@ torture_knownhosts_algorithms(void **state)
+ 
+     algo_list = ssh_client_select_hostkeys(session);
+     assert_non_null(algo_list);
+-    assert_string_equal(algo_list, expect);
++    if (ssh_fips_mode()) {
++        assert_string_equal(algo_list, expect_fips);
++    } else {
++        assert_string_equal(algo_list, expect);
++    }
+     free(algo_list);
+ 
+     ssh_free(session);
+ }
+ 
+-static void
+-torture_knownhosts_algorithms_global(void **state)
++static void torture_knownhosts_algorithms_global(void **state)
+ {
+     const char *knownhosts_file = *state;
+     char *algo_list = NULL;
+     ssh_session session;
++    bool process_config = false;
+     const char *expect = "ssh-ed25519,rsa-sha2-512,rsa-sha2-256,ssh-rsa,"
+                          "ecdsa-sha2-nistp521,ecdsa-sha2-nistp384,"
+                          "ecdsa-sha2-nistp256"
+@@ -500,10 +620,15 @@ torture_knownhosts_algorithms_global(void **state)
+                          ",ssh-dss"
+ #endif
+     ;
++    const char *expect_fips = "rsa-sha2-512,rsa-sha2-256,ecdsa-sha2-nistp521,"
++                              "ecdsa-sha2-nistp384,ecdsa-sha2-nistp256";
+ 
+     session = ssh_new();
+     assert_non_null(session);
+ 
++    /* This makes sure the global configuration file is not processed */
++    ssh_options_set(session, SSH_OPTIONS_PROCESS_CONFIG, &process_config);
++
+     ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
+     /* This makes sure the current-user's known hosts are not used */
+     ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, "/dev/null");
+@@ -511,12 +636,17 @@ torture_knownhosts_algorithms_global(void **state)
+ 
+     algo_list = ssh_client_select_hostkeys(session);
+     assert_non_null(algo_list);
+-    assert_string_equal(algo_list, expect);
++    if (ssh_fips_mode()) {
++        assert_string_equal(algo_list, expect_fips);
++    } else {
++        assert_string_equal(algo_list, expect);
++    }
+     free(algo_list);
+ 
+     ssh_free(session);
+ }
+-#endif
++
++#endif /* _WIN32 There is no /dev/null on Windows */
+ 
+ int torture_run_tests(void) {
+     int rc;
+@@ -538,6 +668,10 @@ int torture_run_tests(void) {
+         cmocka_unit_test_setup_teardown(torture_knownhosts_get_algorithms_names,
+                                         setup_knownhosts_file,
+                                         teardown_knownhosts_file),
++        cmocka_unit_test_setup_teardown(torture_knownhosts_algorithms_wanted,
++                                        setup_knownhosts_file,
++                                        teardown_knownhosts_file),
++        cmocka_unit_test(torture_knownhosts_algorithms_negative),
+ #ifndef _WIN32
+         cmocka_unit_test_setup_teardown(torture_knownhosts_host_exists,
+                                         setup_knownhosts_file,
+-- 
+2.21.0
+
diff --git a/SOURCES/libssh-0.9.0-run-sshd-confined.patch b/SOURCES/libssh-0.9.0-run-sshd-confined.patch
new file mode 100644
index 0000000..4bc62bb
--- /dev/null
+++ b/SOURCES/libssh-0.9.0-run-sshd-confined.patch
@@ -0,0 +1,67 @@
+--- a/tests/torture.c	2019-06-28 14:01:52.936462964 +0200
++++ b/tests/torture.c	2019-06-28 14:03:52.324325029 +0200
+@@ -854,7 +854,7 @@
+     s = *state;
+ 
+     snprintf(sshd_start_cmd, sizeof(sshd_start_cmd),
+-             "/usr/sbin/sshd -r -f %s -E %s/sshd/daemon.log 2> %s/sshd/cwrap.log",
++             "runcon -t sshd_t -u system_u -r system_r /usr/sbin/sshd -r -f %s -E %s/sshd/daemon.log 2> %s/sshd/cwrap.log",
+              s->srv_config, s->socket_dir, s->socket_dir);
+ 
+     rc = system(sshd_start_cmd);
+@@ -864,7 +864,7 @@
+     unsetenv("PAM_WRAPPER");
+ 
+     /* Wait until the sshd is ready to accept connections */
+-    rc = torture_wait_for_daemon(5);
++    rc = torture_wait_for_daemon(10);
+     assert_int_equal(rc, 0);
+ }
+ 
+@@ -904,27 +904,32 @@
+ torture_reload_sshd_server(void **state)
+ {
+     struct torture_state *s = *state;
+-    pid_t pid;
++    char sshd_start_cmd[1024];
+     int rc;
+ 
+-    /* read the pidfile */
+-    pid = torture_read_pidfile(s->srv_pidfile);
+-    assert_int_not_equal(pid, -1);
++    rc = torture_terminate_process(s->srv_pidfile);
++    if (rc != 0) {
++        fprintf(stderr, "XXXXXX Failed to terminate sshd\n");
++    }
+ 
+-    kill(pid, SIGHUP);
++    usleep(100 * 1000);
+ 
+-    /* 10 ms */
+-    usleep(10 * 1000);
++    /* Set the default interface for the server */
++    setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "10", 1);
++    setenv("PAM_WRAPPER", "1", 1);
+ 
+-    rc = kill(pid, 0);
+-    if (rc != 0) {
+-        fprintf(stderr,
+-                "ERROR: SSHD process %u died during reload!\n", pid);
+-        return SSH_ERROR;
+-    }
++    snprintf(sshd_start_cmd, sizeof(sshd_start_cmd),
++             "runcon -t sshd_t -u system_u -r system_r /usr/sbin/sshd -r -f %s -E %s/sshd/daemon.log 2> %s/sshd/cwrap.log",
++             s->srv_config, s->socket_dir, s->socket_dir);
++
++    rc = system(sshd_start_cmd);
++    assert_return_code(rc, errno);
++
++    setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "21", 1);
++    unsetenv("PAM_WRAPPER");
+ 
+     /* Wait until the sshd is ready to accept connections */
+-    rc = torture_wait_for_daemon(5);
++    rc = torture_wait_for_daemon(10);
+     assert_int_equal(rc, 0);
+     return SSH_OK;
+ }
diff --git a/SOURCES/libssh-0.9.0-skip-1k-rsa-key-generation-test.patch b/SOURCES/libssh-0.9.0-skip-1k-rsa-key-generation-test.patch
new file mode 100644
index 0000000..f45a27d
--- /dev/null
+++ b/SOURCES/libssh-0.9.0-skip-1k-rsa-key-generation-test.patch
@@ -0,0 +1,59 @@
+From bf2ed2ca929e5e12279f85c930f8fbb452ada888 Mon Sep 17 00:00:00 2001
+From: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
+Date: Tue, 30 Jul 2019 18:22:30 +0200
+Subject: [PATCH] tests: Skip testing 1024 bits key generation in FIPS mode
+
+In torture_threads_pki_rsa, skip the test which generates 1024 bits RSA
+key pair when in FIPS mode.
+
+Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
+---
+ tests/unittests/torture_threads_pki_rsa.c | 28 ++++++++++++-----------
+ 1 file changed, 15 insertions(+), 13 deletions(-)
+
+diff --git a/tests/unittests/torture_threads_pki_rsa.c b/tests/unittests/torture_threads_pki_rsa.c
+index 5a841ee9..03d526cd 100644
+--- a/tests/unittests/torture_threads_pki_rsa.c
++++ b/tests/unittests/torture_threads_pki_rsa.c
+@@ -571,23 +571,25 @@ static void *thread_pki_rsa_generate_key(void *threadid)
+     session = ssh_new();
+     assert_non_null(session);
+ 
+-    rc = ssh_pki_generate(SSH_KEYTYPE_RSA, 1024, &key);
+-    assert_ssh_return_code(session, rc);
+-    assert_non_null(key);
++    if (!ssh_fips_mode()) {
++        rc = ssh_pki_generate(SSH_KEYTYPE_RSA, 1024, &key);
++        assert_ssh_return_code(session, rc);
++        assert_non_null(key);
+ 
+-    rc = ssh_pki_export_privkey_to_pubkey(key, &pubkey);
+-    assert_int_equal(rc, SSH_OK);
+-    assert_non_null(pubkey);
++        rc = ssh_pki_export_privkey_to_pubkey(key, &pubkey);
++        assert_int_equal(rc, SSH_OK);
++        assert_non_null(pubkey);
+ 
+-    sign = pki_do_sign(key, RSA_HASH, 20, SSH_DIGEST_SHA256);
+-    assert_non_null(sign);
++        sign = pki_do_sign(key, RSA_HASH, 20, SSH_DIGEST_SHA256);
++        assert_non_null(sign);
+ 
+-    rc = pki_signature_verify(session, sign, pubkey, RSA_HASH, 20);
+-    assert_ssh_return_code(session, rc);
++        rc = pki_signature_verify(session, sign, pubkey, RSA_HASH, 20);
++        assert_ssh_return_code(session, rc);
+ 
+-    ssh_signature_free(sign);
+-    SSH_KEY_FREE(key);
+-    SSH_KEY_FREE(pubkey);
++        ssh_signature_free(sign);
++        SSH_KEY_FREE(key);
++        SSH_KEY_FREE(pubkey);
++    }
+ 
+     rc = ssh_pki_generate(SSH_KEYTYPE_RSA, 2048, &key);
+     assert_ssh_return_code(session, rc);
+-- 
+2.21.0
+
diff --git a/SOURCES/libssh-0.9.0.tar.xz.asc b/SOURCES/libssh-0.9.0.tar.xz.asc
new file mode 100644
index 0000000..880c31b
--- /dev/null
+++ b/SOURCES/libssh-0.9.0.tar.xz.asc
@@ -0,0 +1,16 @@
+-----BEGIN PGP SIGNATURE-----
+
+iQIzBAABCAAdFiEEjf9T4Y8qvI2PPJIjfuD8TcwBTj0FAl0VtfEACgkQfuD8TcwB
+Tj0cthAApYglGlE2+f06uKvPUc8LvzVkRFJA5ycm7uMddrMbSJ+ElScEu1a6q/qV
+xPK3w49WdDpbYcz3s/GtdhGkSTye49Zav2PJzDFWvac+PoXVOwt7C5JzlPSq7kfa
+0i6k1/7YSiPcFCo7467v2fpg0t80OHgS+Tbc1mwI0KtRzPA2pjqHsnu+RVNc6EA1
+paUf1QMhjPFIQwcqJcQGAHZBqpx4JBspzBpC7wDxQKFh5FfMbVOxPG3qvgeOYDqd
+cbfsJkdOJQ0rAxyNBB6xbz8XktJyK4Bjg5eT9GEz+zpsjh8jtfJMhNEemaBLXkug
++4wb4DU2uhEuOoOFh0YOgLcRLm2INNhVSTcizasmA8X1YcvAUmKB7fUMuYwOQOPZ
+bsSkJ8kg7v76Y8w/pUger99pVYg0iiLi9KI6a2t7qTSibZewv38IV6eSJqORnZja
+SLeswZUAAtHK/nTf7ohZ8Blnhx3UE5M6vyuli+KMmHAxTOzHhyWJvYDYJ2oJ7+tR
+N49U1O77VE0WYY7HoyEXYkvSwWLb+MYK6ueaJTVBEbq7ZdpzQBQtPLoyCXUdQwZ2
+DyZaaZnhkn9FYvsJp/twHra3XlQ359EXdMwflISaKgFUpfaluLIu1xRGrYH4XPNm
+FHZRPCj34PY1uDOKHXiRl/xUdaR4CSIKPgofhxzy/mLZepJR9vU=
+=xGD9
+-----END PGP SIGNATURE-----
diff --git a/SOURCES/libssh_client.config b/SOURCES/libssh_client.config
new file mode 100644
index 0000000..1d293bd
--- /dev/null
+++ b/SOURCES/libssh_client.config
@@ -0,0 +1,4 @@
+# Parse system-wide crypto configuration file
+Include /etc/crypto-policies/back-ends/libssh.config
+# Parse OpenSSH configuration file for consistency
+Include /etc/ssh/ssh_config
diff --git a/SOURCES/libssh_server.config b/SOURCES/libssh_server.config
new file mode 100644
index 0000000..279b5a3
--- /dev/null
+++ b/SOURCES/libssh_server.config
@@ -0,0 +1,4 @@
+# Parse system-wide crypto configuration file
+Include /etc/crypto-policies/back-ends/libssh.config
+# Parse OpenSSH configuration file for consistency
+Include /etc/ssh/sshd_config
diff --git a/SPECS/libssh.spec b/SPECS/libssh.spec
index 968f6a2..925aa8f 100644
--- a/SPECS/libssh.spec
+++ b/SPECS/libssh.spec
@@ -1,18 +1,19 @@
 Name:           libssh
-Version:        0.8.5
-Release:        2%{?dist}
+Version:        0.9.0
+Release:        4%{?dist}
 Summary:        A library implementing the SSH protocol
 License:        LGPLv2+
 URL:            http://www.libssh.org
 
-Source0:        https://www.libssh.org/files/0.8/%{name}-%{version}.tar.xz
-Source1:        https://www.libssh.org/files/0.8/%{name}-%{version}.tar.xz.asc
+Source0:        https://www.libssh.org/files/0.9/%{name}-%{version}.tar.xz
+Source1:        https://www.libssh.org/files/0.9/%{name}-%{version}.tar.xz.asc
 Source2:        https://cryptomilk.org/gpgkey-8DFF53E18F2ABC8D8F3C92237EE0FC4DCC014E3D.gpg#/%{name}.keyring
+Source3:        libssh_client.config
+Source4:        libssh_server.config
 
-Patch1:         libssh-0.8.5-make-sure-both-known-hosts-ready.patch
-Patch2:         libssh-0.8.5-ensure-ssh-session-fd-writable.patch
-Patch3:         libssh-0.8.5-allow-msg-ext-info.patch
-Patch4:         libssh-0.8.5-allow-kex-init.patch
+Patch0:         libssh-0.9.0-run-sshd-confined.patch
+Patch1:         libssh-0.9.0-do-not-ignore-known-hosts-keys.patch
+Patch2:         libssh-0.9.0-skip-1k-rsa-key-generation-test.patch
 
 BuildRequires:  cmake
 BuildRequires:  doxygen
@@ -24,6 +25,9 @@ BuildRequires:  zlib-devel
 BuildRequires:  krb5-devel
 BuildRequires:  libcmocka-devel
 
+Requires:       crypto-policies
+Requires:       %{name}-config = %{version}-%{release}
+
 %ifarch aarch64 ppc64 ppc64le s390x x86_64
 Provides: libssh_threads.so()(64bit)
 Provides: libssh_threads.so.4()(64bit)
@@ -48,6 +52,14 @@ Requires:       %{name}%{?_isa} = %{version}-%{release}
 The %{name}-devel package contains libraries and header files for developing
 applications that use %{name}.
 
+%package config
+Summary:        Configuration files for %{name}
+BuildArch:      noarch
+Obsoletes:      %{name} < 0.9.0-1
+
+%description config
+The %{name}-config package provides the default configuration files for %{name}.
+
 %prep
 gpgv2 --quiet --keyring %{SOURCE2} %{SOURCE1} %{SOURCE0}
 %autosetup -p1
@@ -59,7 +71,10 @@ fi
 pushd obj
 
 %cmake .. \
-    -DUNIT_TESTING=ON
+    -DUNIT_TESTING=ON \
+    -DGLOBAL_CLIENT_CONFIG="%{_sysconfdir}/libssh/libssh_client.config" \
+    -DGLOBAL_BIND_CONFIG="%{_sysconfdir}/libssh/libssh_server.config"
+
 
 %make_build VERBOSE=1
 make docs
@@ -68,6 +83,9 @@ popd
 
 %install
 make DESTDIR=%{buildroot} install/fast -C obj
+install -d -m755 %{buildroot}%{_sysconfdir}/libssh
+install -m644 %{SOURCE3} %{buildroot}%{_sysconfdir}/libssh/libssh_client.config
+install -m644 %{SOURCE4} %{buildroot}%{_sysconfdir}/libssh/libssh_server.config
 
 #
 # Workaround for the removal of libssh_threads.so
@@ -109,7 +127,35 @@ popd
 %{_libdir}/pkgconfig/libssh.pc
 %{_libdir}/libssh.so
 
+%files config
+%attr(0755,root,root) %dir %{_sysconfdir}/libssh
+%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/libssh/libssh_client.config
+%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/libssh/libssh_server.config
+
 %changelog
+* Mon Aug 05 2019 Anderson Sasaki <ansasaki@redhat.com> - 0.9.0-4
+- Skip 1024 bits RSA key generation test in FIPS mode (#1734485)
+
+* Thu Jul 11 2019 Anderson Sasaki <ansasaki@redhat.com> - 0.9.0-3
+- Add Obsoletes in libssh-config to avoid conflict with old libssh which
+  installed the configuration files.
+
+* Wed Jul 10 2019 Anderson Sasaki <ansasaki@redhat.com> - 0.9.0-2
+- Eliminate circular dependency with libssh-config subpackage
+
+* Wed Jul 10 2019 Anderson Sasaki <ansasaki@redhat.com> - 0.9.0-1
+- Update to version 0.9.0
+  https://www.libssh.org/2019/06/28/libssh-0-9-0/
+- Added explicit Requires for crypto-policies
+- Do not ignore known_hosts keys when SSH_OPTIONS_HOSTKEYS is set
+- Provide the configuration files in a separate libssh-config subpackage
+
+* Mon Jun 17 2019 Anderson Sasaki <ansasaki@redhat.com> - 0.8.91-0.1
+- Update to 0.9.0 pre release version (0.8.91)
+- Added default configuration files for client and server
+- Removed unused patch files left behind
+- Fixed issues found to run upstream test suite with SELinux
+
 * Fri Dec 14 2018 Anderson Sasaki <ansasaki@redhat.com> - 0.8.5-2
 - Fix more regressions introduced by the fixes for CVE-2018-10933