[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] add mbedtls crypto support


This patch adds support for mbedTLS as a crypto backend for libssh.
mbedTLS is an SSL/TLS library that has been designed to mainly be used
in embedded systems.  It is loosely coupled and has a low memory
footprint.  mbedTLS also provides a cryptography library (libmbedcrypto)
that can be used without the TLS modules.

Signed-off-by: Juraj Vijtiuk <juraj.vijtiuk@xxxxxxxxxx>
---
v1:
* The patch has been tested with a Debug and MinSizeRel build, with
libssh unit tests, client tests and the pkd tests.
* All the tests have been run with valgrind's memcheck, drd and helgrind
tools.
* The examples/samplessh client works when built with the patch.
* The patch is unfortunately quite big, since several new files had to
be added.
* DSA is disabled at compile time, since mbedTLS doesn't support DSA
* Patch review and feedback would be appreciated, and if any issues or
suggestions appear, I'm willing to work on them.
---
 CMakeLists.txt                     |   11 +-
 ConfigureChecks.cmake              |   13 +-
 DefineOptions.cmake                |    1 +
 cmake/Modules/FindMbedTLS.cmake    |  104 +++
 config.h.cmake                     |    6 +
 include/libssh/bignum.h            |    1 +
 include/libssh/bind.h              |    4 +
 include/libssh/crypto.h            |    6 +
 include/libssh/ecdh.h              |    4 +
 include/libssh/keys.h              |    4 +
 include/libssh/libmbedcrypto.h     |  111 +++
 include/libssh/libssh.h            |    4 +
 include/libssh/pki.h               |    6 +
 include/libssh/pki_priv.h          |    6 +
 include/libssh/server.h            |    2 +
 include/libssh/session.h           |    2 +
 include/libssh/wrapper.h           |    1 +
 src/CMakeLists.txt                 |   19 +
 src/auth.c                         |    4 +
 src/bignum.c                       |   12 +
 src/bind.c                         |   22 +-
 src/curve25519.c                   |    8 +
 src/dh.c                           |   29 +
 src/ecdh_mbedcrypto.c              |  265 ++++++++
 src/kex.c                          |   12 +
 src/known_hosts.c                  |    6 +
 src/legacy.c                       |   26 +
 src/libcrypto-compat.c             |    2 +
 src/libcrypto.c                    |    6 +-
 src/libmbedcrypto.c                | 1109 ++++++++++++++++++++++++++++++
 src/mbedcrypto_missing.c           |  126 ++++
 src/misc.c                         |   58 +-
 src/options.c                      |   16 +-
 src/pki.c                          |   67 +-
 src/pki_container_openssh.c        |    2 +
 src/pki_crypto.c                   |    2 +
 src/pki_mbedcrypto.c               | 1300 ++++++++++++++++++++++++++++++++++++
 src/server.c                       |    4 +
 src/session.c                      |    4 +
 src/threads.c                      |   32 +
 src/wrapper.c                      |    8 +-
 tests/client/torture_knownhosts.c  |   14 +
 tests/pkd/pkd_daemon.c             |    2 +
 tests/pkd/pkd_daemon.h             |    2 +
 tests/pkd/pkd_hello.c              |   99 +++
 tests/pkd/pkd_keyutil.c            |    8 +
 tests/pkd/pkd_keyutil.h            |   10 +
 tests/test_ssh_bind_accept_fd.c    |    8 +
 tests/torture.c                    |   22 +
 tests/unittests/torture_keyfiles.c |   18 +
 tests/unittests/torture_misc.c     |  142 ++++
 tests/unittests/torture_options.c  |    8 +
 tests/unittests/torture_pki.c      |   53 +-
 53 files changed, 3765 insertions(+), 46 deletions(-)
 create mode 100644 cmake/Modules/FindMbedTLS.cmake
 create mode 100644 include/libssh/libmbedcrypto.h
 create mode 100644 src/ecdh_mbedcrypto.c
 create mode 100644 src/libmbedcrypto.c
 create mode 100644 src/mbedcrypto_missing.c
 create mode 100644 src/pki_mbedcrypto.c

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 30b1025c..a496a5b3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -49,12 +49,20 @@ if (WITH_GCRYPT)
   if (NOT GCRYPT_FOUND)
     message(FATAL_ERROR "Could not find GCrypt")
   endif (NOT GCRYPT_FOUND)
+elseif(WITH_MBEDTLS)
+    find_package(MbedTLS REQUIRED)
+    if (NOT MBEDTLS_FOUND)
+      message(FATAL_ERROR "Could not find mbedTLS")
+    endif (NOT MBEDTLS_FOUND)
 else (WITH_GCRYPT)
   find_package(OpenSSL)
   if (NOT OPENSSL_FOUND)
     find_package(GCrypt)
     if (NOT GCRYPT_FOUND)
-      message(FATAL_ERROR "Could not find OpenSSL or GCrypt")
+      find_package(MbedTLS)
+      if (NOT MBEDTLS_FOUND)
+        message(FATAL_ERROR "Could not find OpenSSL, GCrypt or mbedTLS")
+      endif (NOT MBEDTLS_FOUND)
     endif (NOT GCRYPT_FOUND)
   endif (NOT OPENSSL_FOUND)
 endif(WITH_GCRYPT)
@@ -150,6 +158,7 @@ message(STATUS "********** ${PROJECT_NAME} build options : **********")
 
 message(STATUS "zlib support: ${WITH_ZLIB}")
 message(STATUS "libgcrypt support: ${WITH_GCRYPT}")
+message(STATUS "libmbedTLS support: ${WITH_MBEDTLS}")
 message(STATUS "libnacl support: ${WITH_NACL}")
 message(STATUS "SSH-1 support: ${WITH_SSH1}")
 message(STATUS "SFTP support: ${WITH_SFTP}")
diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake
index f5645807..a814b5eb 100644
--- a/ConfigureChecks.cmake
+++ b/ConfigureChecks.cmake
@@ -124,7 +124,7 @@ if (CMAKE_HAVE_PTHREAD_H)
   set(HAVE_PTHREAD_H 1)
 endif (CMAKE_HAVE_PTHREAD_H)
 
-if (NOT WITH_GCRYPT)
+if (NOT WITH_GCRYPT AND NOT WITH_MBEDTLS)
     if (HAVE_OPENSSL_EC_H AND HAVE_OPENSSL_ECDSA_H)
         set(HAVE_OPENSSL_ECC 1)
     endif (HAVE_OPENSSL_EC_H AND HAVE_OPENSSL_ECDSA_H)
@@ -132,7 +132,11 @@ if (NOT WITH_GCRYPT)
     if (HAVE_OPENSSL_ECC)
         set(HAVE_ECC 1)
     endif (HAVE_OPENSSL_ECC)
-endif (NOT WITH_GCRYPT)
+endif ()
+
+if (NOT WITH_MBEDTLS)
+    set(HAVE_DSA 1)
+endif()
 
 # FUNCTIONS
 
@@ -223,6 +227,11 @@ if (GCRYPT_FOUND)
     endif (GCRYPT_VERSION VERSION_GREATER "1.4.6")
 endif (GCRYPT_FOUND)
 
+if (MBEDTLS_FOUND)
+    set(HAVE_LIBMBEDCRYPTO 1)
+    set(HAVE_ECC 1)
+endif (MBEDTLS_FOUND)
+
 if (CMAKE_USE_PTHREADS_INIT)
     set(HAVE_PTHREAD 1)
 endif (CMAKE_USE_PTHREADS_INIT)
diff --git a/DefineOptions.cmake b/DefineOptions.cmake
index ab7819a5..c7d0b820 100644
--- a/DefineOptions.cmake
+++ b/DefineOptions.cmake
@@ -7,6 +7,7 @@ option(WITH_STATIC_LIB "Build with a static library" OFF)
 option(WITH_DEBUG_CRYPTO "Build with cryto debug output" OFF)
 option(WITH_DEBUG_CALLTRACE "Build with calltrace debug output" ON)
 option(WITH_GCRYPT "Compile against libgcrypt" OFF)
+option(WITH_MBEDTLS "Compile against libmbedtls" OFF)
 option(WITH_PCAP "Compile with Pcap generation support" ON)
 option(WITH_INTERNAL_DOC "Compile doxygen internal documentation" OFF)
 option(WITH_TESTING "Build with unit tests" OFF)
diff --git a/cmake/Modules/FindMbedTLS.cmake b/cmake/Modules/FindMbedTLS.cmake
new file mode 100644
index 00000000..baec8adc
--- /dev/null
+++ b/cmake/Modules/FindMbedTLS.cmake
@@ -0,0 +1,104 @@
+# - Try to find mbedTLS
+# Once done this will define
+#
+#  MBEDTLS_FOUND - system has mbedTLS
+#  MBEDTLS_INCLUDE_DIRS - the mbedTLS include directory
+#  MBEDTLS_LIBRARIES - Link these to use mbedTLS
+#  MBEDTLS_DEFINITIONS - Compiler switches required for using mbedTLS
+#=============================================================================
+#  Copyright (c) 2017 Sartura d.o.o.
+#
+#  Author: Juraj Vijtiuk <juraj.vijtiuk@xxxxxxxxxx>
+#
+#  Distributed under the OSI-approved BSD License (the "License");
+#  see accompanying file Copyright.txt for details.
+#
+#  This software is distributed WITHOUT ANY WARRANTY; without even the
+#  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#  See the License for more information.
+#=============================================================================
+#
+
+
+set(_MBEDTLS_ROOT_HINTS
+    $ENV{MBEDTLS_ROOT_DIR}
+    ${MBEDTLS_ROOT_DIR})
+
+set(_MBEDTLS_ROOT_PATHS
+    "$ENV{PROGRAMFILES}/libmbedtls")
+
+set(_MBEDTLS_ROOT_HINTS_AND_PATHS
+    HINTS ${_MBEDTLS_ROOT_HINTS}
+    PATHS ${_MBEDTLS_ROOT_PATHS})
+
+
+find_path(MBEDTLS_INCLUDE_DIR
+    NAMES
+        mbedtls/config.h
+    HINTS
+        ${_MBEDTLS_ROOT_HINTS_AND_PATHS}
+    PATH_SUFFIXES
+       include
+)
+
+find_library(MBEDTLS_SSL_LIBRARY
+        NAMES
+            mbedtls
+        HINTS
+            ${_MBEDTLS_ROOT_HINTS_AND_PATHS}
+        PATH_SUFFIXES
+            lib
+
+)
+
+find_library(MBEDTLS_CRYPTO_LIBRARY
+        NAMES
+            mbedcrypto
+        HINTS
+            ${_MBEDTLS_ROOT_HINTS_AND_PATHS}
+        PATH_SUFFIXES
+            lib
+)
+
+find_library(MBEDTLS_X509_LIBRARY
+        NAMES
+            mbedx509
+        HINTS
+            ${_MBEDTLS_ROOT_HINTS_AND_PATHS}
+        PATH_SUFFIXES
+            lib
+)
+
+set(MBEDTLS_LIBRARIES ${MBEDTLS_SSL_LIBRARY} ${MBEDTLS_CRYPTO_LIBRARY}
+        ${MBEDTLS_X509_LIBRARY})
+
+if (MBEDTLS_INCLUDE_DIR AND EXISTS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h")
+    file(STRINGS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h" _mbedtls_version_str REGEX
+            "^#[\t ]*define[\t ]+MBEDTLS_VERSION_STRING[\t ]+\"[0-9]+.[0-9]+.[0-9]+\"")
+
+    string(REGEX REPLACE "^.*MBEDTLS_VERSION_STRING.*([0-9]+.[0-9]+.[0-9]+).*"
+            "\\1" MBEDTLS_VERSION "${_mbedtls_version_str}")
+endif ()
+
+include(FindPackageHandleStandardArgs)
+if (MBEDTLS_VERSION)
+    find_package_handle_standard_args(MbedTLS
+        REQUIRED_VARS
+            MBEDTLS_INCLUDE_DIR
+            MBEDTLS_LIBRARIES
+        VERSION_VAR
+            MBEDTLS_VERSION
+        FAIL_MESSAGE
+            "Could NOT find mbedTLS, try to set the path to mbedTLS root folder
+            in the system variable MBEDTLS_ROOT_DIR"
+    )
+else (MBEDTLS_VERSION)
+    find_package_handle_standard_args(MBedTLS
+        "Could NOT find mbedTLS, try to set the path to mbedLS root folder in
+        the system variable MBEDTLS_ROOT_DIR"
+        MBEDTLS_INCLUDE_DIR
+        MBEDTLS_LIBRARIES)
+endif (MBEDTLS_VERSION)
+
+# show the MBEDTLS_INCLUDE_DIRS and MBEDTLS_LIBRARIES variables only in the advanced view
+mark_as_advanced(MBEDTLS_INCLUDE_DIR MBEDTLS_LIBRARIES)
diff --git a/config.h.cmake b/config.h.cmake
index 3f34f09b..e183c6c7 100644
--- a/config.h.cmake
+++ b/config.h.cmake
@@ -80,6 +80,9 @@
 /* Define to 1 if you have eliptic curve cryptography */
 #cmakedefine HAVE_ECC 1
 
+/* Define to 1 if you have DSA */
+#cmakedefine HAVE_DSA 1
+
 /*************************** FUNCTIONS ***************************/
 
 /* Define to 1 if you have the `EVP_aes128_ctr' function. */
@@ -159,6 +162,9 @@
 /* Define to 1 if you have the `gcrypt' library (-lgcrypt). */
 #cmakedefine HAVE_LIBGCRYPT 1
 
+/* Define to 1 if you have the 'mbedTLS' library (-lmbedtls). */
+#cmakedefine HAVE_LIBMBEDCRYPTO 1
+
 /* Define to 1 if you have the `pthread' library (-lpthread). */
 #cmakedefine HAVE_PTHREAD 1
 
diff --git a/include/libssh/bignum.h b/include/libssh/bignum.h
index 71970e3e..32727050 100644
--- a/include/libssh/bignum.h
+++ b/include/libssh/bignum.h
@@ -23,6 +23,7 @@
 
 #include "libssh/libcrypto.h"
 #include "libssh/libgcrypt.h"
+#include "libssh/libmbedcrypto.h"
 
 bignum ssh_make_string_bn(ssh_string string);
 void ssh_make_string_bn_inplace(ssh_string string, bignum bnout);
diff --git a/include/libssh/bind.h b/include/libssh/bind.h
index edbc7b77..6f4425c9 100644
--- a/include/libssh/bind.h
+++ b/include/libssh/bind.h
@@ -34,11 +34,15 @@ struct ssh_bind_struct {
   char *wanted_methods[10];
   char *banner;
   char *ecdsakey;
+#ifdef HAVE_DSA
   char *dsakey;
+#endif
   char *rsakey;
   char *ed25519key;
   ssh_key ecdsa;
+#ifdef HAVE_DSA
   ssh_key dsa;
+#endif
   ssh_key rsa;
   ssh_key ed25519;
   char *bindaddr;
diff --git a/include/libssh/crypto.h b/include/libssh/crypto.h
index 4c79c8ca..9e602028 100644
--- a/include/libssh/crypto.h
+++ b/include/libssh/crypto.h
@@ -80,6 +80,8 @@ struct ssh_crypto_struct {
     EC_KEY *ecdh_privkey;
 #elif defined HAVE_GCRYPT_ECC
     gcry_sexp_t ecdh_privkey;
+#elif defined HAVE_LIBMBEDCRYPTO
+    mbedtls_ecp_keypair *ecdh_privkey;
 #endif
     ssh_string ecdh_client_pubkey;
     ssh_string ecdh_server_pubkey;
@@ -131,6 +133,10 @@ struct ssh_cipher_struct {
     struct ssh_aes_key_schedule *aes_key;
     const EVP_CIPHER *cipher;
     EVP_CIPHER_CTX *ctx;
+#elif defined HAVE_LIBMBEDCRYPTO
+    mbedtls_cipher_context_t encrypt_ctx;
+    mbedtls_cipher_context_t decrypt_ctx;
+    mbedtls_cipher_type_t type;
 #endif
     unsigned int keysize; /* bytes of key used. != keylen */
     /* sets the new key for immediate use */
diff --git a/include/libssh/ecdh.h b/include/libssh/ecdh.h
index 9f94d69c..66659b85 100644
--- a/include/libssh/ecdh.h
+++ b/include/libssh/ecdh.h
@@ -37,6 +37,10 @@
 #define HAVE_ECDH 1
 #endif
 
+#ifdef HAVE_LIBMBEDCRYPTO
+#define HAVE_ECDH 1
+#endif
+
 /* Common functions.  */
 int ssh_client_ecdh_reply(ssh_session session, ssh_buffer packet);
 
diff --git a/include/libssh/keys.h b/include/libssh/keys.h
index 6f08e070..e3603c42 100644
--- a/include/libssh/keys.h
+++ b/include/libssh/keys.h
@@ -34,6 +34,8 @@ struct ssh_public_key_struct {
 #elif HAVE_LIBCRYPTO
     DSA *dsa_pub;
     RSA *rsa_pub;
+#elif HAVE_LIBMBEDCRYPTO
+    mbedtls_pk_context *rsa_pub;
 #endif
 };
 
@@ -45,6 +47,8 @@ struct ssh_private_key_struct {
 #elif defined HAVE_LIBCRYPTO
     DSA *dsa_priv;
     RSA *rsa_priv;
+#elif HAVE_LIBMBEDCRYPTO
+    mbedtls_pk_context *rsa_priv;
 #endif
 };
 
diff --git a/include/libssh/libmbedcrypto.h b/include/libssh/libmbedcrypto.h
new file mode 100644
index 00000000..7cc1bbb0
--- /dev/null
+++ b/include/libssh/libmbedcrypto.h
@@ -0,0 +1,111 @@
+/*
+ * This file is part of the SSH Library
+ *
+ * Copyright (c) 2017 Sartura d.o.o.
+ *
+ * Author: Juraj Vijtiuk <juraj.vijtiuk@xxxxxxxxxx>
+ *
+ * The SSH Library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ *
+ * The SSH Library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the SSH Library; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#ifndef LIBMBEDCRYPTO_H_
+#define LIBMBEDCRYPTO_H_
+
+#include "config.h"
+
+#ifdef HAVE_LIBMBEDCRYPTO
+
+#include <mbedtls/md.h>
+#include <mbedtls/bignum.h>
+#include <mbedtls/pk.h>
+#include <mbedtls/cipher.h>
+#include <mbedtls/entropy.h>
+#include <mbedtls/ctr_drbg.h>
+
+typedef mbedtls_md_context_t *SHACTX;
+typedef mbedtls_md_context_t *SHA256CTX;
+typedef mbedtls_md_context_t *SHA384CTX;
+typedef mbedtls_md_context_t *SHA512CTX;
+typedef mbedtls_md_context_t *MD5CTX;
+typedef mbedtls_md_context_t *HMACCTX;
+typedef mbedtls_md_context_t *EVPCTX;
+
+#define SHA_DIGEST_LENGTH 20
+#define SHA_DIGEST_LEN SHA_DIGEST_LENGTH
+#define MD5_DIGEST_LEN 16
+#define SHA256_DIGEST_LENGTH 32
+#define SHA256_DIGEST_LEN SHA256_DIGEST_LENGTH
+#define SHA384_DIGEST_LENGTH 48
+#define SHA384_DIGEST_LEN SHA384_DIGEST_LENGTH
+#define SHA512_DIGEST_LENGTH 64
+#define SHA512_DIGEST_LEN SHA512_DIGEST_LENGTH
+
+#ifndef EVP_MAX_MD_SIZE
+#define EVP_MAX_MD_SIZE 64
+#endif
+
+#define EVP_DIGEST_LEN EVP_MAX_MD_SIZE
+
+typedef mbedtls_mpi *bignum;
+
+/* Constants for curves */
+#define NID_mbedtls_nistp256 0
+#define NID_mbedtls_nistp384 1
+#define NID_mbedtls_nistp521 2
+
+struct mbedtls_ecdsa_sig {
+    bignum r;
+    bignum s;
+};
+
+bignum ssh_mbedcry_bn_new(void);
+void ssh_mbedcry_bn_free(bignum num);
+char *ssh_mbedcry_bn2num(bignum num, int radix);
+int ssh_mbedcry_rand(bignum rnd, int bits, int top, int bottom);
+int ssh_mbedcry_is_bit_set(bignum num, size_t pos);
+
+#define bignum_new() ssh_mbedcry_bn_new()
+#define bignum_free(num) ssh_mbedcry_bn_free(num);
+#define bignum_set_word(bn, n) mbedtls_mpi_lset(bn, n) /* TODO fix
+                                                          overflow/underflow */
+#define bignum_bin2bn(data, datalen, bn) mbedtls_mpi_read_binary(bn, data, \
+        datalen)
+#define bignum_bn2dec(num) ssh_mbedcry_bn2num(num, 10)
+#define bignum_dec2bn(data, bn) mbedtls_mpi_read_string(bn, 10, data)
+#define bignum_bn2hex(num) ssh_mbedcry_bn2num(num, 16)
+#define bignum_rand(rnd, bits, top, bottom) ssh_mbedcry_rand(rnd, bits, \
+        top, bottom)
+#define bignum_mod_exp(dest, generator, exp, modulo, ctx) \
+        mbedtls_mpi_exp_mod(dest, generator, exp, modulo, NULL)
+#define bignum_num_bytes(num) mbedtls_mpi_size(num)
+#define bignum_num_bits(num) mbedtls_mpi_bitlen(num)
+#define bignum_is_bit_set(num, bit) ssh_mbedcry_is_bit_set(num, bit)
+#define bignum_bn2bin(num, ptr) mbedtls_mpi_write_binary(num, ptr, \
+        mbedtls_mpi_size(num))
+#define bignum_cmp(num1, num2) mbedtls_mpi_cmp_mpi(num1, num2)
+
+mbedtls_entropy_context ssh_mbedtls_entropy;
+mbedtls_ctr_drbg_context ssh_mbedtls_ctr_drbg;
+
+void ssh_mbedtls_init(void);
+void ssh_mbedtls_cleanup(void);
+int ssh_mbedtls_random(void *where, int len, int strong);
+
+ssh_string make_ecpoint_string(const mbedtls_ecp_group *g, const
+        mbedtls_ecp_point *p);
+
+#endif /* HAVE_LIBMBEDCRYPTO */
+#endif /* LIBMBEDCRYPTO_H_ */
diff --git a/include/libssh/libssh.h b/include/libssh/libssh.h
index 504a645a..d8757406 100644
--- a/include/libssh/libssh.h
+++ b/include/libssh/libssh.h
@@ -253,12 +253,16 @@ enum ssh_error_types_e {
 /* some types for keys */
 enum ssh_keytypes_e{
   SSH_KEYTYPE_UNKNOWN=0,
+#ifdef HAVE_DSA
   SSH_KEYTYPE_DSS=1,
+#endif
   SSH_KEYTYPE_RSA,
   SSH_KEYTYPE_RSA1,
   SSH_KEYTYPE_ECDSA,
   SSH_KEYTYPE_ED25519,
+#ifdef HAVE_DSA
   SSH_KEYTYPE_DSS_CERT01,
+#endif
   SSH_KEYTYPE_RSA_CERT01
 };
 
diff --git a/include/libssh/pki.h b/include/libssh/pki.h
index e0e30f1a..46ce6457 100644
--- a/include/libssh/pki.h
+++ b/include/libssh/pki.h
@@ -48,6 +48,9 @@ struct ssh_key_struct {
     gcry_sexp_t dsa;
     gcry_sexp_t rsa;
     gcry_sexp_t ecdsa;
+#elif HAVE_LIBMBEDCRYPTO
+    mbedtls_pk_context *rsa;
+    mbedtls_ecdsa_context *ecdsa;
 #elif HAVE_LIBCRYPTO
     DSA *dsa;
     RSA *rsa;
@@ -78,6 +81,9 @@ struct ssh_signature_struct {
 # else
     void *ecdsa_sig;
 # endif
+#elif defined HAVE_LIBMBEDCRYPTO
+    ssh_string rsa_sig;
+    struct mbedtls_ecdsa_sig ecdsa_sig;
 #endif
     ed25519_signature *ed25519_sig;
 };
diff --git a/include/libssh/pki_priv.h b/include/libssh/pki_priv.h
index 9a8857dc..7dfd49aa 100644
--- a/include/libssh/pki_priv.h
+++ b/include/libssh/pki_priv.h
@@ -34,8 +34,10 @@ int bcrypt_pbkdf(const char *pass,
 
 #define RSA_HEADER_BEGIN "-----BEGIN RSA PRIVATE KEY-----"
 #define RSA_HEADER_END "-----END RSA PRIVATE KEY-----"
+#ifdef HAVE_DSA
 #define DSA_HEADER_BEGIN "-----BEGIN DSA PRIVATE KEY-----"
 #define DSA_HEADER_END "-----END DSA PRIVATE KEY-----"
+#endif
 #define ECDSA_HEADER_BEGIN "-----BEGIN EC PRIVATE KEY-----"
 #define ECDSA_HEADER_END "-----END EC PRIVATE KEY-----"
 #define OPENSSH_HEADER_BEGIN "-----BEGIN OPENSSH PRIVATE KEY-----"
@@ -49,7 +51,9 @@ const char *pki_key_ecdsa_nid_to_name(int nid);
 /* SSH Key Functions */
 ssh_key pki_key_dup(const ssh_key key, int demote);
 int pki_key_generate_rsa(ssh_key key, int parameter);
+#ifdef HAVE_DSA
 int pki_key_generate_dss(ssh_key key, int parameter);
+#endif
 int pki_key_generate_ecdsa(ssh_key key, int parameter);
 int pki_key_generate_ed25519(ssh_key key);
 
@@ -70,11 +74,13 @@ ssh_string pki_private_key_to_pem(const ssh_key key,
                                   void *auth_data);
 
 /* SSH Public Key Functions */
+#ifdef HAVE_DSA
 int pki_pubkey_build_dss(ssh_key key,
                          ssh_string p,
                          ssh_string q,
                          ssh_string g,
                          ssh_string pubkey);
+#endif
 int pki_pubkey_build_rsa(ssh_key key,
                          ssh_string e,
                          ssh_string n);
diff --git a/include/libssh/server.h b/include/libssh/server.h
index c2132de1..b76b95b3 100644
--- a/include/libssh/server.h
+++ b/include/libssh/server.h
@@ -40,7 +40,9 @@ enum ssh_bind_options_e {
   SSH_BIND_OPTIONS_BINDPORT,
   SSH_BIND_OPTIONS_BINDPORT_STR,
   SSH_BIND_OPTIONS_HOSTKEY,
+#ifdef HAVE_DSA
   SSH_BIND_OPTIONS_DSAKEY,
+#endif
   SSH_BIND_OPTIONS_RSAKEY,
   SSH_BIND_OPTIONS_BANNER,
   SSH_BIND_OPTIONS_LOG_VERBOSITY,
diff --git a/include/libssh/session.h b/include/libssh/session.h
index 60d78578..3357f7f3 100644
--- a/include/libssh/session.h
+++ b/include/libssh/session.h
@@ -154,7 +154,9 @@ struct ssh_session_struct {
     /* server host keys */
     struct {
         ssh_key rsa_key;
+#ifdef HAVE_DSA
         ssh_key dsa_key;
+#endif
         ssh_key ecdsa_key;
         ssh_key ed25519_key;
         /* The type of host key wanted by client */
diff --git a/include/libssh/wrapper.h b/include/libssh/wrapper.h
index cdd72d6d..6b6cf0b1 100644
--- a/include/libssh/wrapper.h
+++ b/include/libssh/wrapper.h
@@ -25,6 +25,7 @@
 #include "libssh/libssh.h"
 #include "libssh/libcrypto.h"
 #include "libssh/libgcrypt.h"
+#include "libssh/libmbedcrypto.h"
 
 enum ssh_mac_e {
   SSH_MAC_SHA1=1,
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index e5a93538..da87313e 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -39,6 +39,17 @@ if (OPENSSL_CRYPTO_LIBRARY)
   )
 endif (OPENSSL_CRYPTO_LIBRARY)
 
+if (MBEDTLS_CRYPTO_LIBRARY)
+    set(LIBSSH_PRIVATE_INCLUDE_DIRS
+      ${LIBSSH_PRIVATE_INCLUDE_DIRS}
+      ${MBEDTLS_INCLUDE_DIR}
+    )
+  set(LIBSSH_LINK_LIBRARIES
+    ${LIBSSH_LINK_LIBRARIES}
+    ${MBEDTLS_CRYPTO_LIBRARY}
+  )
+endif (MBEDTLS_CRYPTO_LIBRARY)
+
 if (GCRYPT_LIBRARY)
   set(LIBSSH_PRIVATE_INCLUDE_DIRS
     ${LIBSSH_PRIVATE_INCLUDE_DIRS}
@@ -160,6 +171,14 @@ if (WITH_GCRYPT)
         pki_gcrypt.c
         ecdh_gcrypt.c
        )
+elseif (WITH_MBEDTLS)
+    set(libssh_SRCS
+        ${libssh_SRCS}
+        libmbedcrypto.c
+        mbedcrypto_missing.c
+        pki_mbedcrypto.c
+        ecdh_mbedcrypto.c
+       )
 else (WITH_GCRYPT)
     set(libssh_SRCS
         ${libssh_SRCS}
diff --git a/src/auth.c b/src/auth.c
index 8a686dc2..c92e3073 100644
--- a/src/auth.c
+++ b/src/auth.c
@@ -1206,12 +1206,16 @@ int ssh_userauth_agent_pubkey(ssh_session session,
     key->type = publickey->type;
     key->type_c = ssh_key_type_to_char(key->type);
     key->flags = SSH_KEY_FLAG_PUBLIC;
+#ifdef HAVE_DSA
     key->dsa = publickey->dsa_pub;
+#endif
     key->rsa = publickey->rsa_pub;
 
     rc = ssh_userauth_agent_publickey(session, username, key);
 
+#ifdef HAVE_DSA
     key->dsa = NULL;
+#endif
     key->rsa = NULL;
     ssh_key_free(key);
 
diff --git a/src/bignum.c b/src/bignum.c
index fd6cf954..93e67e7d 100644
--- a/src/bignum.c
+++ b/src/bignum.c
@@ -58,6 +58,8 @@ ssh_string ssh_make_bignum_string(bignum num) {
   bignum_bn2bin(num, len, ptr->data + pad);
 #elif HAVE_LIBCRYPTO
   bignum_bn2bin(num, ptr->data + pad);
+#elif HAVE_LIBMBEDCRYPTO
+  bignum_bn2bin(num, ptr->data + pad);
 #endif
 
   return ptr;
@@ -76,6 +78,9 @@ bignum ssh_make_string_bn(ssh_string string){
   bignum_bin2bn(string->data, len, &bn);
 #elif defined HAVE_LIBCRYPTO
   bn = bignum_bin2bn(string->data, len, NULL);
+#elif defined HAVE_LIBMBEDCRYPTO
+  bn = bignum_new();
+  bignum_bin2bn(string->data, len, bn);
 #endif
 
   return bn;
@@ -89,6 +94,8 @@ void ssh_make_string_bn_inplace(ssh_string string, bignum bnout) {
   (void) bnout;
 #elif defined HAVE_LIBCRYPTO
   bignum_bin2bn(string->data, len, bnout);
+#elif defined HAVE_LIBMBEDCRYPTO
+  bignum_bin2bn(string->data, len, bnout);
 #endif
 }
 
@@ -100,6 +107,9 @@ void ssh_print_bignum(const char *which, const bignum num) {
 #elif defined HAVE_LIBCRYPTO
   char *hex = NULL;
   hex = bignum_bn2hex(num);
+#elif defined HAVE_LIBMBEDCRYPTO
+  char *hex = NULL;
+  hex = bignum_bn2hex(num);
 #endif
   fprintf(stderr, "%s value: ", which);
   fprintf(stderr, "%s\n", (hex == NULL) ? "(null)" : (char *) hex);
@@ -107,5 +117,7 @@ void ssh_print_bignum(const char *which, const bignum num) {
   SAFE_FREE(hex);
 #elif defined HAVE_LIBCRYPTO
   OPENSSL_free(hex);
+#elif defined HAVE_LIBMBEDCRYPTO
+  SAFE_FREE(hex);
 #endif
 }
diff --git a/src/bind.c b/src/bind.c
index fa5f8d57..2b41fe18 100644
--- a/src/bind.c
+++ b/src/bind.c
@@ -148,7 +148,9 @@ static int ssh_bind_import_keys(ssh_bind sshbind) {
   int rc;
 
   if (sshbind->ecdsakey == NULL &&
+#ifdef HAVE_DSA
       sshbind->dsakey == NULL &&
+#endif
       sshbind->rsakey == NULL) {
       ssh_set_error(sshbind, SSH_FATAL,
                     "ECDSA, DSA, or RSA host key file must be set");
@@ -178,6 +180,7 @@ static int ssh_bind_import_keys(ssh_bind sshbind) {
   }
 #endif
 
+#ifdef HAVE_DSA
   if (sshbind->dsa == NULL && sshbind->dsakey != NULL) {
       rc = ssh_pki_import_privkey_file(sshbind->dsakey,
                                        NULL,
@@ -199,6 +202,7 @@ static int ssh_bind_import_keys(ssh_bind sshbind) {
           return SSH_ERROR;
       }
   }
+#endif
 
   if (sshbind->rsa == NULL && sshbind->rsakey != NULL) {
       rc = ssh_pki_import_privkey_file(sshbind->rsakey,
@@ -235,7 +239,11 @@ int ssh_bind_listen(ssh_bind sshbind) {
     return -1;
   }
 
-  if (sshbind->rsa == NULL && sshbind->dsa == NULL && sshbind->ecdsa == NULL) {
+  if (sshbind->rsa == NULL &&
+#ifdef HAVE_DSA
+          sshbind->dsa == NULL &&
+#endif
+          sshbind->ecdsa == NULL) {
       rc = ssh_bind_import_keys(sshbind);
       if (rc != SSH_OK) {
           return SSH_ERROR;
@@ -250,8 +258,10 @@ int ssh_bind_listen(ssh_bind sshbind) {
 
       fd = bind_socket(sshbind, host, sshbind->bindport);
       if (fd == SSH_INVALID_SOCKET) {
+#ifdef HAVE_DSA
           ssh_key_free(sshbind->dsa);
           sshbind->dsa = NULL;
+#endif
           ssh_key_free(sshbind->rsa);
           sshbind->rsa = NULL;
           return -1;
@@ -262,8 +272,10 @@ int ssh_bind_listen(ssh_bind sshbind) {
                   "Listening to socket %d: %s",
                   fd, strerror(errno));
           CLOSE_SOCKET(fd);
+#ifdef HAVE_DSA
           ssh_key_free(sshbind->dsa);
           sshbind->dsa = NULL;
+#endif
           ssh_key_free(sshbind->rsa);
           sshbind->rsa = NULL;
           return -1;
@@ -360,13 +372,17 @@ void ssh_bind_free(ssh_bind sshbind){
   SAFE_FREE(sshbind->banner);
   SAFE_FREE(sshbind->bindaddr);
 
+#ifdef HAVE_DSA
   SAFE_FREE(sshbind->dsakey);
+#endif
   SAFE_FREE(sshbind->rsakey);
   SAFE_FREE(sshbind->ecdsakey);
   SAFE_FREE(sshbind->ed25519key);
 
+#ifdef HAVE_DSA
   ssh_key_free(sshbind->dsa);
   sshbind->dsa = NULL;
+#endif
   ssh_key_free(sshbind->rsa);
   sshbind->rsa = NULL;
   ssh_key_free(sshbind->ecdsa);
@@ -433,7 +449,9 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd){
      * only using ssh_bind_accept_fd to manage sockets ourselves.
      */
     if (sshbind->rsa == NULL &&
+#ifdef HAVE_DSA
         sshbind->dsa == NULL &&
+#endif
         sshbind->ecdsa == NULL) {
         rc = ssh_bind_import_keys(sshbind);
         if (rc != SSH_OK) {
@@ -450,6 +468,7 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd){
         }
     }
 #endif
+#ifdef HAVE_DSA
     if (sshbind->dsa) {
         session->srv.dsa_key = ssh_key_dup(sshbind->dsa);
         if (session->srv.dsa_key == NULL) {
@@ -457,6 +476,7 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd){
           return SSH_ERROR;
         }
     }
+#endif
     if (sshbind->rsa) {
         session->srv.rsa_key = ssh_key_dup(sshbind->rsa);
         if (session->srv.rsa_key == NULL) {
diff --git a/src/curve25519.c b/src/curve25519.c
index 77fab2d2..6d9a409c 100644
--- a/src/curve25519.c
+++ b/src/curve25519.c
@@ -78,6 +78,12 @@ static int ssh_curve25519_build_k(ssh_session session) {
   if (session->next_crypto->k == NULL) {
     return SSH_ERROR;
   }
+#elif defined HAVE_LIBMBEDCRYPTO
+  session->next_crypto->k = bignum_new();
+
+  if (session->next_crypto->k == NULL) {
+    return SSH_ERROR;
+  }
 #endif
 
   if (session->server)
@@ -91,6 +97,8 @@ static int ssh_curve25519_build_k(ssh_session session) {
   bignum_bin2bn(k, CURVE25519_PUBKEY_SIZE, &session->next_crypto->k);
 #elif defined HAVE_LIBCRYPTO
   bignum_bin2bn(k, CURVE25519_PUBKEY_SIZE, session->next_crypto->k);
+#elif defined HAVE_LIBMBEDCRYPTO
+  bignum_bin2bn(k, CURVE25519_PUBKEY_SIZE, session->next_crypto->k);
 #endif
 
 #ifdef DEBUG_CRYPTO
diff --git a/src/dh.c b/src/dh.c
index c54bb9f1..b547d6f8 100644
--- a/src/dh.c
+++ b/src/dh.c
@@ -136,6 +136,8 @@ int ssh_get_random(void *where, int len, int strong){
   } else {
     return RAND_pseudo_bytes(where,len);
   }
+#elif defined HAVE_LIBMBEDCRYPTO
+  return ssh_mbedtls_random(where, len, strong);
 #endif
 
   /* never reached */
@@ -155,6 +157,8 @@ int ssh_crypto_init(void) {
       gcry_control(GCRYCTL_INIT_SECMEM, 4096);
       gcry_control(GCRYCTL_INITIALIZATION_FINISHED,0);
     }
+#elif HAVE_LIBMBEDCRYPTO
+    ssh_mbedtls_init();
 #endif
 
     g = bignum_new();
@@ -199,7 +203,12 @@ int ssh_crypto_init(void) {
     bignum_bin2bn(p_group14_value, P_GROUP14_LEN, p_group14);
 
     OpenSSL_add_all_algorithms();
+#elif defined HAVE_LIBMBEDCRYPTO
+    p_group1 = bignum_new();
+    bignum_bin2bn(p_group1_value, P_GROUP1_LEN, p_group1);
 
+    p_group14 = bignum_new();
+    bignum_bin2bn(p_group14_value, P_GROUP14_LEN, p_group14);
 #endif
 
     ssh_crypto_initialized = 1;
@@ -221,6 +230,8 @@ void ssh_crypto_finalize(void) {
 #elif defined HAVE_LIBCRYPTO
     EVP_cleanup();
     CRYPTO_cleanup_all_ex_data();
+#elif defined HAVE_LIBMBEDTLS
+    ssh_mbedtls_cleanup();
 #endif
     ssh_crypto_initialized=0;
   }
@@ -242,6 +253,8 @@ int ssh_dh_generate_x(ssh_session session) {
   bignum_rand(session->next_crypto->x, keysize);
 #elif defined HAVE_LIBCRYPTO
   bignum_rand(session->next_crypto->x, keysize, -1, 0);
+#elif defined HAVE_LIBMBEDCRYPTO
+  bignum_rand(session->next_crypto->x, keysize, -1, 0);
 #endif
 
   /* not harder than this */
@@ -269,6 +282,8 @@ int ssh_dh_generate_y(ssh_session session) {
   bignum_rand(session->next_crypto->y, keysize);
 #elif defined HAVE_LIBCRYPTO
   bignum_rand(session->next_crypto->y, keysize, -1, 0);
+#elif defined HAVE_LIBMBEDCRYPTO
+  bignum_rand(session->next_crypto->y, keysize, -1, 0);
 #endif
 
   /* not harder than this */
@@ -302,6 +317,9 @@ int ssh_dh_generate_e(ssh_session session) {
 #elif defined HAVE_LIBCRYPTO
   bignum_mod_exp(session->next_crypto->e, g, session->next_crypto->x,
       select_p(session->next_crypto->kex_type), ctx);
+#elif defined HAVE_LIBMBEDCRYPTO
+  bignum_mod_exp(session->next_crypto->e, g, session->next_crypto->x,
+      select_p(session->next_crypto->kex_type), NULL);
 #endif
 
 #ifdef DEBUG_CRYPTO
@@ -337,6 +355,9 @@ int ssh_dh_generate_f(ssh_session session) {
 #elif defined HAVE_LIBCRYPTO
   bignum_mod_exp(session->next_crypto->f, g, session->next_crypto->y,
       select_p(session->next_crypto->kex_type), ctx);
+#elif defined HAVE_LIBMBEDCRYPTO
+  bignum_mod_exp(session->next_crypto->f, g, session->next_crypto->y,
+      select_p(session->next_crypto->kex_type), NULL);
 #endif
 
 #ifdef DEBUG_CRYPTO
@@ -423,6 +444,14 @@ int ssh_dh_build_k(ssh_session session) {
     bignum_mod_exp(session->next_crypto->k, session->next_crypto->e,
         session->next_crypto->y, select_p(session->next_crypto->kex_type), ctx);
   }
+#elif defined HAVE_LIBMBEDCRYPTO
+  if (session->client) {
+    bignum_mod_exp(session->next_crypto->k, session->next_crypto->f,
+        session->next_crypto->x, select_p(session->next_crypto->kex_type), NULL);
+  } else {
+    bignum_mod_exp(session->next_crypto->k, session->next_crypto->e,
+        session->next_crypto->y, select_p(session->next_crypto->kex_type), NULL);
+  }
 #endif
 
 #ifdef DEBUG_CRYPTO
diff --git a/src/ecdh_mbedcrypto.c b/src/ecdh_mbedcrypto.c
new file mode 100644
index 00000000..344260c5
--- /dev/null
+++ b/src/ecdh_mbedcrypto.c
@@ -0,0 +1,265 @@
+/*
+ * This file is part of the SSH Library
+ *
+ * Copyright (c) 2017 Sartura d.o.o.
+ *
+ * Author: Juraj Vijtiuk <juraj.vijtiuk@xxxxxxxxxx>
+ *
+ * The SSH Library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ *
+ * The SSH Library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the SSH Library; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#include "config.h"
+#include "libssh/session.h"
+#include "libssh/ecdh.h"
+#include "libssh/buffer.h"
+#include "libssh/ssh2.h"
+#include "libssh/dh.h"
+#include "libssh/pki.h"
+#include "libssh/bignum.h"
+#include "libssh/libmbedcrypto.h"
+
+#include <mbedtls/ecdh.h>
+#include <mbedtls/ecp.h>
+
+#ifdef HAVE_ECDH
+int ssh_client_ecdh_init(ssh_session session)
+{
+    ssh_string client_pubkey = NULL;
+    mbedtls_ecp_group grp;
+    int rc;
+
+    rc = ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_KEX_ECDH_INIT);
+    if (rc < 0) {
+        return SSH_ERROR;
+    }
+
+    session->next_crypto->ecdh_privkey = malloc(sizeof(mbedtls_ecp_keypair));
+    if (session->next_crypto->ecdh_privkey == NULL) {
+        return SSH_ERROR;
+    }
+
+    mbedtls_ecp_keypair_init(session->next_crypto->ecdh_privkey);
+    mbedtls_ecp_group_init(&grp);
+
+    rc = mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1);
+    if (rc != 0) {
+        rc = SSH_ERROR;
+        goto out;
+    }
+
+    rc = mbedtls_ecp_gen_keypair(&grp, &session->next_crypto->ecdh_privkey->d,
+            &session->next_crypto->ecdh_privkey->Q, mbedtls_ctr_drbg_random,
+            &ssh_mbedtls_ctr_drbg);
+
+    if (rc != 0) {
+        rc = SSH_ERROR;
+        goto out;
+    }
+
+    client_pubkey = make_ecpoint_string(&grp,
+            &session->next_crypto->ecdh_privkey->Q);
+    if (client_pubkey == NULL) {
+        rc = SSH_ERROR;
+        goto out;
+    }
+
+    rc = ssh_buffer_add_ssh_string(session->out_buffer, client_pubkey);
+    if (rc < 0) {
+        rc = SSH_ERROR;
+        goto out;
+    }
+
+    session->next_crypto->ecdh_client_pubkey = client_pubkey;
+    client_pubkey = NULL;
+
+    rc = ssh_packet_send(session);
+
+out:
+    mbedtls_ecp_group_free(&grp);
+    if (client_pubkey != NULL) {
+        ssh_string_free(client_pubkey);
+    }
+
+    return rc;
+}
+
+int ecdh_build_k(ssh_session session)
+{
+    mbedtls_ecp_group grp;
+    mbedtls_ecp_point pubkey;
+    int rc;
+
+    mbedtls_ecp_group_init(&grp);
+    mbedtls_ecp_point_init(&pubkey);
+
+    rc = mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1);
+    if (rc != 0) {
+        rc = SSH_ERROR;
+        goto out;
+    }
+
+    if (session->server) {
+        rc = mbedtls_ecp_point_read_binary(&grp, &pubkey,
+                ssh_string_data(session->next_crypto->ecdh_client_pubkey),
+                ssh_string_len(session->next_crypto->ecdh_client_pubkey));
+    } else {
+        rc = mbedtls_ecp_point_read_binary(&grp, &pubkey,
+                ssh_string_data(session->next_crypto->ecdh_server_pubkey),
+                ssh_string_len(session->next_crypto->ecdh_server_pubkey));
+    }
+
+    if (rc != 0) {
+        rc = SSH_ERROR;
+        goto out;
+    }
+
+    session->next_crypto->k = malloc(sizeof(mbedtls_mpi));
+    if (session->next_crypto->k == NULL) {
+        rc = SSH_ERROR;
+        goto out;
+    }
+
+    mbedtls_mpi_init(session->next_crypto->k);
+
+    rc = mbedtls_ecdh_compute_shared(&grp, session->next_crypto->k, &pubkey,
+            &session->next_crypto->ecdh_privkey->d, mbedtls_ctr_drbg_random,
+            &ssh_mbedtls_ctr_drbg);
+    if (rc != 0) {
+        rc = SSH_ERROR;
+        goto out;
+    }
+
+out:
+    mbedtls_ecp_keypair_free(session->next_crypto->ecdh_privkey);
+    SAFE_FREE(session->next_crypto->ecdh_privkey);
+    mbedtls_ecp_group_free(&grp);
+    mbedtls_ecp_point_free(&pubkey);
+    return rc;
+}
+
+#ifdef WITH_SERVER
+int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet)
+{
+    ssh_string q_c_string;
+    ssh_string q_s_string;
+    mbedtls_ecp_group grp;
+    ssh_key privkey;
+    ssh_string sig_blob = NULL;
+    int rc;
+
+    q_c_string = ssh_buffer_get_ssh_string(packet);
+    if (q_c_string == NULL) {
+        ssh_set_error(session, SSH_FATAL, "No Q_C ECC point in packet");
+        return SSH_ERROR;
+    }
+
+    session->next_crypto->ecdh_privkey = malloc(sizeof(mbedtls_ecp_keypair));
+    if (session->next_crypto->ecdh_privkey == NULL) {
+        return SSH_ERROR;
+    }
+
+    session->next_crypto->ecdh_client_pubkey = q_c_string;
+
+    mbedtls_ecp_group_init(&grp);
+    mbedtls_ecp_keypair_init(session->next_crypto->ecdh_privkey);
+
+    rc = mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1);
+    if (rc != 0) {
+        rc = SSH_ERROR;
+        goto out;
+    }
+
+    rc = mbedtls_ecp_gen_keypair(&grp, &session->next_crypto->ecdh_privkey->d,
+            &session->next_crypto->ecdh_privkey->Q, mbedtls_ctr_drbg_random,
+            &ssh_mbedtls_ctr_drbg);
+    if (rc != 0) {
+        rc = SSH_ERROR;
+        goto out;
+    }
+
+    q_s_string = make_ecpoint_string(&grp, &session->next_crypto->ecdh_privkey->Q);
+    if (q_s_string == NULL) {
+        rc = SSH_ERROR;
+        goto out;
+    }
+
+    session->next_crypto->ecdh_server_pubkey = q_s_string;
+
+    /* build k and session_id */
+    rc = ecdh_build_k(session);
+    if (rc != SSH_OK) {
+        ssh_set_error(session, SSH_FATAL, "Cannot build k number");
+        goto out;
+    }
+
+    /* privkey is not allocated */
+    rc = ssh_get_key_params(session, &privkey);
+    if (rc == SSH_ERROR) {
+        rc = SSH_ERROR;
+        goto out;
+    }
+
+    rc = ssh_make_sessionid(session);
+    if (rc != SSH_OK) {
+        ssh_set_error(session, SSH_FATAL, "Could not create a session id");
+        rc = SSH_ERROR;
+        goto out;
+    }
+
+    sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey);
+    if (sig_blob == NULL) {
+        ssh_set_error(session, SSH_FATAL, "Could not sign the session id");
+        rc = SSH_ERROR;
+        goto out;
+    }
+
+    rc = ssh_buffer_pack(session->out_buffer, "bSSS",
+            SSH2_MSG_KEXDH_REPLY, session->next_crypto->server_pubkey,
+            q_s_string,
+            sig_blob);
+
+    ssh_string_free(sig_blob);
+
+    if (rc != SSH_OK) {
+        ssh_set_error_oom(session);
+        rc = SSH_ERROR;
+        goto out;
+    }
+
+    SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEXDH_REPLY sent");
+    rc = ssh_packet_send(session);
+    if (rc != SSH_OK) {
+        rc = SSH_ERROR;
+        goto out;
+    }
+
+    rc = ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS);
+    if (rc < 0) {
+        rc = SSH_ERROR;
+        goto out;
+    }
+
+    session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
+    rc = ssh_packet_send(session);
+    SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
+
+out:
+    mbedtls_ecp_group_free(&grp);
+    return rc;
+}
+
+#endif /* WITH_SERVER */
+#endif
diff --git a/src/kex.c b/src/kex.c
index f34728c7..5f222147 100644
--- a/src/kex.c
+++ b/src/kex.c
@@ -43,6 +43,12 @@
 # define DES "3des-cbc"
 # define DES_SUPPORTED "3des-cbc,des-cbc-ssh1"
 
+#elif defined HAVE_LIBMBEDCRYPTO
+# define BLOWFISH "blowfish-cbc,"
+# define AES "aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc,aes192-cbc,aes128-cbc,"
+# define DES "3des-cbc"
+# define DES_SUPPORTED "3des-cbc,des-cbc-ssh1"
+
 #elif defined(HAVE_LIBCRYPTO)
 
 # ifdef HAVE_OPENSSL_BLOWFISH_H
@@ -81,7 +87,11 @@
 #define ECDH "ecdh-sha2-nistp256,"
 #define HOSTKEYS "ssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-rsa,ssh-dss"
 #else
+#ifdef HAVE_DSA
 #define HOSTKEYS "ssh-ed25519,ssh-rsa,ssh-dss"
+#else
+#define HOSTKEYS "ssh-ed25519,ssh-rsa"
+#endif
 #define ECDH ""
 #endif
 
@@ -495,7 +505,9 @@ static char *ssh_client_select_hostkeys(ssh_session session){
         "ecdsa-sha2-nistp384",
         "ecdsa-sha2-nistp256",
         "ssh-rsa",
+#ifdef HAVE_DSA
         "ssh-dss",
+#endif
         "ssh-rsa1",
         NULL
     };
diff --git a/src/known_hosts.c b/src/known_hosts.c
index 2f66cc27..354da176 100644
--- a/src/known_hosts.c
+++ b/src/known_hosts.c
@@ -220,7 +220,11 @@ static int check_public_key(ssh_session session, char **tokens) {
 
     for (i = 2; i < 4; i++) { /* e, then n */
       tmpbn = NULL;
+#ifdef HAVE_LIBMBEDCRYPTO
+      bignum_dec2bn(tokens[i], tmpbn);
+#else
       bignum_dec2bn(tokens[i], &tmpbn);
+#endif
       if (tmpbn == NULL) {
         ssh_buffer_free(pubkey_buffer);
         return -1;
@@ -242,6 +246,8 @@ static int check_public_key(ssh_session session, char **tokens) {
       bignum_bn2bin(tmpbn, len, ssh_string_data(tmpstring));
 #elif defined HAVE_LIBCRYPTO
       bignum_bn2bin(tmpbn, ssh_string_data(tmpstring));
+#elif defined HAVE_LIBMBEDCRYPTO
+      bignum_bn2bin(tmpbn, ssh_string_data(tmpstring));
 #endif
       bignum_free(tmpbn);
       if (ssh_buffer_add_ssh_string(pubkey_buffer, tmpstring) < 0) {
diff --git a/src/legacy.c b/src/legacy.c
index 3f09992c..7f43f59c 100644
--- a/src/legacy.c
+++ b/src/legacy.c
@@ -82,11 +82,15 @@ int ssh_userauth_pubkey(ssh_session session,
     key->type = privatekey->type;
     key->type_c = ssh_key_type_to_char(key->type);
     key->flags = SSH_KEY_FLAG_PRIVATE|SSH_KEY_FLAG_PUBLIC;
+#ifdef HAVE_DSA
     key->dsa = privatekey->dsa_priv;
+#endif
     key->rsa = privatekey->rsa_priv;
 
     rc = ssh_userauth_publickey(session, username, key);
+#ifdef HAVE_DSA
     key->dsa = NULL;
+#endif
     key->rsa = NULL;
     ssh_key_free(key);
 
@@ -349,6 +353,7 @@ void publickey_free(ssh_public_key key) {
   }
 
   switch(key->type) {
+#ifdef HAVE_DSA
     case SSH_KEYTYPE_DSS:
 #ifdef HAVE_LIBGCRYPT
       gcry_sexp_release(key->dsa_pub);
@@ -356,12 +361,16 @@ void publickey_free(ssh_public_key key) {
       DSA_free(key->dsa_pub);
 #endif
       break;
+#endif
     case SSH_KEYTYPE_RSA:
     case SSH_KEYTYPE_RSA1:
 #ifdef HAVE_LIBGCRYPT
       gcry_sexp_release(key->rsa_pub);
 #elif defined HAVE_LIBCRYPTO
       RSA_free(key->rsa_pub);
+#elif defined HAVE_LIBMBEDCRYPTO
+      mbedtls_pk_free(key->rsa_pub);
+      SAFE_FREE(key->rsa_pub);
 #endif
       break;
     default:
@@ -384,11 +393,15 @@ ssh_public_key publickey_from_privatekey(ssh_private_key prv) {
     privkey->type = prv->type;
     privkey->type_c = ssh_key_type_to_char(privkey->type);
     privkey->flags = SSH_KEY_FLAG_PRIVATE | SSH_KEY_FLAG_PUBLIC;
+#ifdef HAVE_DSA
     privkey->dsa = prv->dsa_priv;
+#endif
     privkey->rsa = prv->rsa_priv;
 
     rc = ssh_pki_export_privkey_to_pubkey(privkey, &pubkey);
+#ifdef HAVE_DSA
     privkey->dsa = NULL;
+#endif
     privkey->rsa = NULL;
     ssh_key_free(privkey);
     if (rc < 0) {
@@ -435,10 +448,14 @@ ssh_private_key privatekey_from_file(ssh_session session,
     }
 
     privkey->type = key->type;
+#ifdef HAVE_DSA
     privkey->dsa_priv = key->dsa;
+#endif
     privkey->rsa_priv = key->rsa;
 
+#ifdef HAVE_DSA
     key->dsa = NULL;
+#endif
     key->rsa = NULL;
 
     ssh_key_free(key);
@@ -463,6 +480,9 @@ void privatekey_free(ssh_private_key prv) {
 #elif defined HAVE_LIBCRYPTO
   DSA_free(prv->dsa_priv);
   RSA_free(prv->rsa_priv);
+#elif defined HAVE_LIBMBEDCRYPTO
+  mbedtls_pk_free(prv->rsa_priv);
+  SAFE_FREE(prv->rsa_priv);
 #endif
   memset(prv, 0, sizeof(struct ssh_private_key_struct));
   SAFE_FREE(prv);
@@ -524,8 +544,10 @@ ssh_public_key publickey_from_string(ssh_session session, ssh_string pubkey_s) {
     pubkey->type = key->type;
     pubkey->type_c = key->type_c;
 
+#ifdef HAVE_DSA
     pubkey->dsa_pub = key->dsa;
     key->dsa = NULL;
+#endif
     pubkey->rsa_pub = key->rsa;
     key->rsa = NULL;
 
@@ -547,7 +569,9 @@ ssh_string publickey_to_string(ssh_public_key pubkey) {
     key->type = pubkey->type;
     key->type_c = pubkey->type_c;
 
+#ifdef HAVE_DSA
     key->dsa = pubkey->dsa_pub;
+#endif
     key->rsa = pubkey->rsa_pub;
 
     rc = ssh_pki_export_pubkey_blob(key, &key_blob);
@@ -555,7 +579,9 @@ ssh_string publickey_to_string(ssh_public_key pubkey) {
         key_blob = NULL;
     }
 
+#ifdef HAVE_DSA
     key->dsa = NULL;
+#endif
     key->rsa = NULL;
     ssh_key_free(key);
 
diff --git a/src/libcrypto-compat.c b/src/libcrypto-compat.c
index 3e1bc71a..45dffbb4 100644
--- a/src/libcrypto-compat.c
+++ b/src/libcrypto-compat.c
@@ -304,9 +304,11 @@ void HMAC_CTX_free(HMAC_CTX *ctx)
 {
     if (ctx != NULL) {
         hmac_ctx_cleanup(ctx);
+#if OPENSSL_VERSION_NUMBER > 0x10100000L
         EVP_MD_CTX_free(&ctx->i_ctx);
         EVP_MD_CTX_free(&ctx->o_ctx);
         EVP_MD_CTX_free(&ctx->md_ctx);
+#endif
         OPENSSL_free(ctx);
     }
 }
diff --git a/src/libcrypto.c b/src/libcrypto.c
index 867bf227..59c99568 100644
--- a/src/libcrypto.c
+++ b/src/libcrypto.c
@@ -422,7 +422,8 @@ void hmac_final(HMACCTX ctx, unsigned char *hashmacbuf, unsigned int *len) {
   HMAC_Final(ctx,hashmacbuf,len);
 
 #ifndef OLD_CRYPTO
-  HMAC_CTX_reset(ctx);
+  HMAC_CTX_free(ctx);
+  ctx = NULL;
 #else
   HMAC_cleanup(ctx);
 #endif
@@ -552,7 +553,10 @@ static void evp_cipher_decrypt(struct ssh_cipher_struct *cipher,
 }
 
 static void evp_cipher_cleanup(struct ssh_cipher_struct *cipher) {
+    if (cipher->ctx != NULL) {
         EVP_CIPHER_CTX_cleanup(cipher->ctx);
+        EVP_CIPHER_CTX_free(cipher->ctx);
+    }
 }
 
 #ifndef HAVE_OPENSSL_EVP_AES_CTR
diff --git a/src/libmbedcrypto.c b/src/libmbedcrypto.c
new file mode 100644
index 00000000..c89033fb
--- /dev/null
+++ b/src/libmbedcrypto.c
@@ -0,0 +1,1109 @@
+/*
+ * This file is part of the SSH Library
+ *
+ * Copyright (c) 2017 Sartura d.o.o.
+ *
+ * Author: Juraj Vijtiuk <juraj.vijtiuk@xxxxxxxxxx>
+ *
+ * The SSH Library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ *
+ * The SSH Library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the SSH Library; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#include "libssh/wrapper.h"
+#include "libssh/crypto.h"
+#include "libssh/priv.h"
+
+#ifdef HAVE_LIBMBEDCRYPTO
+#include <mbedtls/md.h>
+
+struct ssh_mac_ctx_struct {
+    enum ssh_mac_e mac_type;
+    mbedtls_md_context_t ctx;
+};
+
+void ssh_reseed(void)
+{
+}
+
+SHACTX sha1_init(void)
+{
+    SHACTX ctx;
+    int rc;
+    const mbedtls_md_info_t *md_info =
+        mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
+
+    if (md_info == NULL) {
+        return NULL;
+    }
+
+    ctx = malloc(sizeof(mbedtls_md_context_t));
+    if (ctx == NULL) {
+        return NULL;
+    }
+
+    mbedtls_md_init(ctx);
+
+    rc = mbedtls_md_setup(ctx, md_info, 0);
+    if (rc != 0) {
+        return NULL;
+    }
+
+    rc = mbedtls_md_starts(ctx);
+    if (rc != 0) {
+        return NULL;
+    }
+
+    return ctx;
+}
+
+void sha1_update(SHACTX c, const void *data, unsigned long len)
+{
+    mbedtls_md_update(c, data, len);
+}
+
+void sha1_final(unsigned char *md, SHACTX c)
+{
+    mbedtls_md_finish(c, md);
+    mbedtls_md_free(c);
+    SAFE_FREE(c);
+}
+
+void sha1(unsigned char *digest, int len, unsigned char *hash)
+{
+    const mbedtls_md_info_t *md_info =
+        mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
+    if (md_info != NULL) {
+        mbedtls_md(md_info, digest, len, hash);
+    }
+}
+
+static mbedtls_md_type_t nid_to_md_algo(int nid)
+{
+    switch (nid) {
+        case NID_mbedtls_nistp256:
+            return MBEDTLS_MD_SHA256;
+        case NID_mbedtls_nistp384:
+            return MBEDTLS_MD_SHA384;
+        case NID_mbedtls_nistp521:
+            return MBEDTLS_MD_SHA512;
+    }
+    return MBEDTLS_MD_NONE;
+}
+
+void evp(int nid, unsigned char *digest, int len,
+        unsigned char *hash, unsigned int *hlen)
+{
+    mbedtls_md_type_t algo = nid_to_md_algo(nid);
+    const mbedtls_md_info_t *md_info =
+        mbedtls_md_info_from_type(algo);
+
+
+    if (md_info != NULL) {
+        *hlen = mbedtls_md_get_size(md_info);
+        mbedtls_md(md_info, digest, len, hash);
+    }
+}
+
+EVPCTX evp_init(int nid)
+{
+    EVPCTX ctx;
+    int rc;
+    mbedtls_md_type_t algo = nid_to_md_algo(nid);
+    const mbedtls_md_info_t *md_info =
+        mbedtls_md_info_from_type(algo);
+
+    if (md_info == NULL) {
+        return NULL;
+    }
+
+    ctx = malloc(sizeof(mbedtls_md_context_t));
+    if (ctx == NULL) {
+        return NULL;
+    }
+
+    mbedtls_md_init(ctx);
+
+    rc = mbedtls_md_setup(ctx, md_info, 0);
+    if (rc != 0) {
+        return NULL;
+    }
+
+    rc = mbedtls_md_starts(ctx);
+    if (rc != 0) {
+        return NULL;
+    }
+
+    return ctx;
+}
+
+void evp_update(EVPCTX ctx, const void *data, unsigned long len)
+{
+    mbedtls_md_update(ctx, data, len);
+}
+
+void evp_final(EVPCTX ctx, unsigned char *md, unsigned int *mdlen)
+{
+    *mdlen = mbedtls_md_get_size(ctx->md_info);
+    mbedtls_md_hmac_finish(ctx, md);
+    mbedtls_md_free(ctx);
+    SAFE_FREE(ctx);
+}
+
+SHA256CTX sha256_init(void)
+{
+    SHA256CTX ctx;
+    int rc;
+    const mbedtls_md_info_t *md_info =
+        mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
+
+    if (md_info == NULL) {
+        return NULL;
+    }
+
+    ctx = malloc(sizeof(mbedtls_md_context_t));
+    if(ctx == NULL) {
+        return NULL;
+    }
+
+    mbedtls_md_init(ctx);
+
+    rc = mbedtls_md_setup(ctx, md_info, 0);
+    if (rc != 0) {
+        return NULL;
+    }
+
+    rc = mbedtls_md_starts(ctx);
+    if (rc != 0) {
+        return NULL;
+    }
+
+    return ctx;
+}
+
+void sha256_update(SHA256CTX c, const void *data, unsigned long len)
+{
+    mbedtls_md_update(c, data, len);
+}
+
+void sha256_final(unsigned char *md, SHA256CTX c)
+{
+    mbedtls_md_finish(c, md);
+    mbedtls_md_free(c);
+    SAFE_FREE(c);
+}
+
+void sha256(unsigned char *digest, int len, unsigned char *hash)
+{
+    const mbedtls_md_info_t *md_info =
+        mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
+    if (md_info != NULL) {
+        mbedtls_md(md_info, digest, len, hash);
+    }
+}
+
+SHA384CTX sha384_init(void)
+{
+    SHA384CTX ctx;
+    int rc;
+    const mbedtls_md_info_t *md_info =
+        mbedtls_md_info_from_type(MBEDTLS_MD_SHA384);
+
+    if (md_info == NULL) {
+        return NULL;
+    }
+
+    ctx = malloc(sizeof(mbedtls_md_context_t));
+    if (ctx == NULL) {
+        return NULL;
+    }
+
+    mbedtls_md_init(ctx);
+
+    rc = mbedtls_md_setup(ctx, md_info, 0);
+    if (rc != 0) {
+        return NULL;
+    }
+
+    rc = mbedtls_md_starts(ctx);
+    if (rc != 0) {
+        return NULL;
+    }
+
+    return ctx;
+}
+
+void sha384_update(SHA384CTX c, const void *data, unsigned long len)
+{
+    mbedtls_md_update(c, data, len);
+}
+
+void sha384_final(unsigned char *md, SHA384CTX c)
+{
+    mbedtls_md_finish(c, md);
+    mbedtls_md_free(c);
+    SAFE_FREE(c);
+}
+
+void sha384(unsigned char *digest, int len, unsigned char *hash)
+{
+    const mbedtls_md_info_t *md_info =
+        mbedtls_md_info_from_type(MBEDTLS_MD_SHA384);
+    if (md_info != NULL) {
+        mbedtls_md(md_info, digest, len, hash);
+    }
+}
+
+SHA512CTX sha512_init(void)
+{
+    SHA512CTX ctx;
+    int rc;
+    const mbedtls_md_info_t *md_info =
+        mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
+    if (md_info == NULL) {
+        return NULL;
+    }
+
+    ctx = malloc(sizeof(mbedtls_md_context_t));
+    if (ctx == NULL) {
+        return NULL;
+    }
+
+    mbedtls_md_init(ctx);
+
+    rc = mbedtls_md_setup(ctx, md_info, 0);
+    if (rc != 0) {
+        return NULL;
+    }
+
+    rc = mbedtls_md_starts(ctx);
+    if (rc != 0) {
+        return NULL;
+    }
+
+    return ctx;
+}
+
+void sha512_update(SHA512CTX c, const void *data, unsigned long len)
+{
+    mbedtls_md_update(c, data, len);
+}
+
+void sha512_final(unsigned char *md, SHA512CTX c)
+{
+    mbedtls_md_finish(c, md);
+    mbedtls_md_free(c);
+    SAFE_FREE(c);
+}
+
+void sha512(unsigned char *digest, int len, unsigned char *hash)
+{
+    const mbedtls_md_info_t *md_info =
+        mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
+    if (md_info != NULL) {
+        mbedtls_md(md_info, digest, len, hash);
+    }
+}
+
+MD5CTX md5_init(void)
+{
+    MD5CTX ctx;
+    int rc;
+    const mbedtls_md_info_t *md_info =
+        mbedtls_md_info_from_type(MBEDTLS_MD_MD5);
+    if (md_info == NULL) {
+        return NULL;
+    }
+
+    ctx = malloc(sizeof(mbedtls_md_context_t));
+    if (ctx == NULL) {
+        return NULL;
+    }
+
+    mbedtls_md_init(ctx);
+
+    rc = mbedtls_md_setup(ctx, md_info, 0);
+    if (rc != 0) {
+        return NULL;
+    }
+
+    rc = mbedtls_md_starts(ctx);
+    if (rc != 0) {
+        return NULL;
+    }
+
+    return ctx;
+}
+
+
+void md5_update(MD5CTX c, const void *data, unsigned long len) {
+    mbedtls_md_update(c, data, len);
+}
+
+void md5_final(unsigned char *md, MD5CTX c)
+{
+    mbedtls_md_finish(c, md);
+    mbedtls_md_free(c);
+    SAFE_FREE(c);
+}
+
+ssh_mac_ctx ssh_mac_ctx_init(enum ssh_mac_e type)
+{
+    ssh_mac_ctx ctx = malloc(sizeof (struct ssh_mac_ctx_struct));
+    const mbedtls_md_info_t *md_info;
+    int rc;
+    if (ctx == NULL) {
+        return NULL;
+    }
+
+    ctx->mac_type=type;
+    switch(type) {
+        case SSH_MAC_SHA1:
+            md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
+            break;
+        case SSH_MAC_SHA256:
+            md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
+            break;
+        case SSH_MAC_SHA384:
+            md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA384);
+            break;
+        case SSH_MAC_SHA512:
+            md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
+            break;
+        default:
+            goto error;
+    }
+
+    if (md_info == NULL) {
+        goto error;
+    }
+
+    mbedtls_md_init(&ctx->ctx);
+
+    rc = mbedtls_md_setup(&ctx->ctx, md_info, 0);
+    if (rc != 0) {
+        goto error;
+    }
+
+    rc = mbedtls_md_starts(&ctx->ctx);
+    if (rc != 0) {
+        goto error;
+    }
+
+    return ctx;
+
+error:
+    SAFE_FREE(ctx);
+    return NULL;
+}
+
+void ssh_mac_update(ssh_mac_ctx ctx, const void *data, unsigned long len)
+{
+    mbedtls_md_update(&ctx->ctx, data, len);
+}
+
+void ssh_mac_final(unsigned char *md, ssh_mac_ctx ctx)
+{
+    mbedtls_md_finish(&ctx->ctx, md);
+    mbedtls_md_free(&ctx->ctx);
+    SAFE_FREE(ctx);
+}
+
+HMACCTX hmac_init(const void *key, int len, enum ssh_hmac_e type)
+{
+    HMACCTX ctx = NULL;
+    const mbedtls_md_info_t *md_info;
+    int rc;
+
+    ctx = malloc(sizeof(mbedtls_md_context_t));
+    if (ctx == NULL) {
+        return NULL;
+    }
+
+    switch (type) {
+        case SSH_HMAC_SHA1:
+            md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
+            break;
+        case SSH_HMAC_SHA256:
+            md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
+            break;
+        case SSH_HMAC_SHA384:
+            md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA384);
+            break;
+        case SSH_HMAC_SHA512:
+            md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
+            break;
+        default:
+            goto error;
+    }
+
+    mbedtls_md_init(ctx);
+
+    if (md_info == NULL) {
+        goto error;
+    }
+
+    rc = mbedtls_md_setup(ctx, md_info, 1);
+    if (rc != 0) {
+        goto error;
+    }
+
+    rc = mbedtls_md_hmac_starts(ctx, key, len);
+    if (rc != 0) {
+        goto error;
+    }
+
+    return ctx;
+
+error:
+    mbedtls_md_free(ctx);
+    SAFE_FREE(ctx);
+    return NULL;
+}
+
+void hmac_update(HMACCTX c, const void *data, unsigned long len)
+{
+    mbedtls_md_hmac_update(c, data, len);
+}
+
+void hmac_final(HMACCTX c, unsigned char *hashmacbuf, unsigned int *len)
+{
+    *len = mbedtls_md_get_size(c->md_info);
+    mbedtls_md_hmac_finish(c, hashmacbuf);
+    mbedtls_md_free(c);
+    SAFE_FREE(c);
+}
+
+static int cipher_set_encrypt_key(struct ssh_cipher_struct *cipher, void *key,
+        void *IV)
+{
+
+    const mbedtls_cipher_info_t *cipher_info;
+    int rc;
+
+    mbedtls_cipher_init(&cipher->encrypt_ctx);
+    cipher_info = mbedtls_cipher_info_from_type(cipher->type);
+
+    rc = mbedtls_cipher_setup(&cipher->encrypt_ctx, cipher_info);
+    if (rc != 0) {
+        SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setup failed");
+        goto error;
+    }
+
+    rc = mbedtls_cipher_setkey(&cipher->encrypt_ctx, key,
+                               cipher_info->key_bitlen,
+                               MBEDTLS_ENCRYPT);
+    if (rc != 0) {
+        SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setkey failed");
+        goto error;
+    }
+
+    rc = mbedtls_cipher_set_iv(&cipher->encrypt_ctx, IV, cipher_info->iv_size);
+
+    if (rc != 0) {
+        SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_set_iv failed");
+        goto error;
+    }
+
+    rc = mbedtls_cipher_reset(&cipher->encrypt_ctx);
+
+    if (rc != 0) {
+        SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_reset failed");
+        goto error;
+    }
+
+    return SSH_OK;
+error:
+    mbedtls_cipher_free(&cipher->encrypt_ctx);
+    return SSH_ERROR;
+}
+
+static int cipher_set_encrypt_key_cbc(struct ssh_cipher_struct *cipher, void *key,
+        void *IV)
+{
+
+    const mbedtls_cipher_info_t *cipher_info;
+    int rc;
+
+    mbedtls_cipher_init(&cipher->encrypt_ctx);
+    cipher_info = mbedtls_cipher_info_from_type(cipher->type);
+
+    rc = mbedtls_cipher_setup(&cipher->encrypt_ctx, cipher_info);
+    if (rc != 0) {
+        SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setup failed");
+        goto error;
+    }
+
+    rc = mbedtls_cipher_setkey(&cipher->encrypt_ctx, key,
+                               cipher_info->key_bitlen,
+                               MBEDTLS_ENCRYPT);
+    if (rc != 0) {
+        SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setkey failed");
+        goto error;
+    }
+
+    rc = mbedtls_cipher_set_iv(&cipher->encrypt_ctx, IV, cipher_info->iv_size);
+
+    if (rc != 0) {
+        SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_set_iv failed");
+        goto error;
+    }
+
+    /* libssh only encypts and decrypts packets that are multiples of a block
+     * size, and no padding is used */
+    rc = mbedtls_cipher_set_padding_mode(&cipher->encrypt_ctx,
+            MBEDTLS_PADDING_NONE);
+
+    if (rc != 0) {
+        SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_set_padding_mode failed");
+        goto error;
+    }
+
+    rc = mbedtls_cipher_reset(&cipher->encrypt_ctx);
+
+    if (rc != 0) {
+        SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_reset failed");
+        goto error;
+    }
+
+    return SSH_OK;
+error:
+    mbedtls_cipher_free(&cipher->encrypt_ctx);
+    return SSH_ERROR;
+}
+
+static int cipher_set_decrypt_key(struct ssh_cipher_struct *cipher, void *key,
+        void *IV)
+{
+    const mbedtls_cipher_info_t *cipher_info;
+    int rc;
+
+    mbedtls_cipher_init(&cipher->decrypt_ctx);
+    cipher_info = mbedtls_cipher_info_from_type(cipher->type);
+
+    rc = mbedtls_cipher_setup(&cipher->decrypt_ctx, cipher_info);
+    if (rc != 0) {
+        SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setkey failed");
+        goto error;
+    }
+
+    rc = mbedtls_cipher_setkey(&cipher->decrypt_ctx, key,
+                               cipher_info->key_bitlen,
+                               MBEDTLS_DECRYPT);
+    if (rc != 0) {
+        SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setkey failed");
+        goto error;
+    }
+
+    rc = mbedtls_cipher_set_iv(&cipher->decrypt_ctx, IV, cipher_info->iv_size);
+    if (rc != 0) {
+        SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_set_iv failed");
+        goto error;
+    }
+
+    mbedtls_cipher_reset(&cipher->decrypt_ctx);
+
+    if (rc != 0) {
+        SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_reset failed");
+        goto error;
+    }
+
+    return SSH_OK;
+error:
+    mbedtls_cipher_free(&cipher->decrypt_ctx);
+    return SSH_ERROR;
+}
+
+static int cipher_set_decrypt_key_cbc(struct ssh_cipher_struct *cipher, void *key,
+        void *IV)
+{
+    const mbedtls_cipher_info_t *cipher_info;
+    int rc;
+
+    mbedtls_cipher_init(&cipher->decrypt_ctx);
+    cipher_info = mbedtls_cipher_info_from_type(cipher->type);
+
+    rc = mbedtls_cipher_setup(&cipher->decrypt_ctx, cipher_info);
+    if (rc != 0) {
+        SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setkey failed");
+        goto error;
+    }
+
+    rc = mbedtls_cipher_setkey(&cipher->decrypt_ctx, key,
+                               cipher_info->key_bitlen,
+                               MBEDTLS_DECRYPT);
+    if (rc != 0) {
+        SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setkey failed");
+        goto error;
+    }
+
+    rc = mbedtls_cipher_set_iv(&cipher->decrypt_ctx, IV, cipher_info->iv_size);
+    if (rc != 0) {
+        SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_set_iv failed");
+        goto error;
+    }
+
+    rc = mbedtls_cipher_set_padding_mode(&cipher->decrypt_ctx,
+            MBEDTLS_PADDING_NONE);
+
+    if (rc != 0) {
+        SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_set_padding_mode failed");
+        goto error;
+    }
+
+    mbedtls_cipher_reset(&cipher->decrypt_ctx);
+
+    if (rc != 0) {
+        SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_reset failed");
+        goto error;
+    }
+
+    return SSH_OK;
+error:
+    mbedtls_cipher_free(&cipher->decrypt_ctx);
+    return SSH_ERROR;
+}
+
+static void cipher_encrypt(struct ssh_cipher_struct *cipher, void *in, void *out,
+        unsigned long len)
+{
+    size_t outlen = 0;
+    size_t total_len = 0;
+    int rc = 0;
+    rc = mbedtls_cipher_update(&cipher->encrypt_ctx, in, len, out, &outlen);
+    if (rc != 0) {
+        SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_update failed during encryption");
+        return;
+    }
+
+    total_len += outlen;
+
+    if (total_len == len) {
+        return;
+    }
+
+    rc = mbedtls_cipher_finish(&cipher->encrypt_ctx, (unsigned char *) out + outlen,
+            &outlen);
+
+    total_len += outlen;
+
+    if (rc != 0) {
+        SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_finish failed during encryption");
+        return;
+    }
+
+    if (total_len != len) {
+        SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_update: output size %zu for %zu",
+                outlen, len);
+        return;
+    }
+
+}
+
+static void cipher_encrypt_cbc(struct ssh_cipher_struct *cipher, void *in, void *out,
+        unsigned long len)
+{
+    size_t outlen = 0;
+    int rc = 0;
+    rc = mbedtls_cipher_update(&cipher->encrypt_ctx, in, len, out, &outlen);
+    if (rc != 0) {
+        SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_update failed during encryption");
+        return;
+    }
+
+    if (outlen != len) {
+        SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_update: output size %zu for %zu",
+                outlen, len);
+        return;
+    }
+
+}
+
+static void cipher_decrypt(struct ssh_cipher_struct *cipher, void *in, void *out,
+        unsigned long len)
+{
+    size_t outlen = 0;
+    int rc = 0;
+    size_t total_len = 0;
+
+    rc = mbedtls_cipher_update(&cipher->decrypt_ctx, in, len, out, &outlen);
+    if (rc != 0) {
+        SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_update failed during decryption");
+        return;
+    }
+
+    total_len += outlen;
+
+    if (total_len == len) {
+        return;
+    }
+
+    rc = mbedtls_cipher_finish(&cipher->decrypt_ctx, (unsigned char *) out +
+            outlen, &outlen);
+
+    if (rc != 0) {
+        SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_reset failed during decryption");
+        return;
+    }
+
+    total_len += outlen;
+
+    if (total_len != len) {
+        SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_update: output size %zu for %zu",
+                outlen, len);
+        return;
+    }
+
+}
+
+static void cipher_decrypt_cbc(struct ssh_cipher_struct *cipher, void *in, void *out,
+        unsigned long len)
+{
+    size_t outlen = 0;
+    int rc = 0;
+    rc = mbedtls_cipher_update(&cipher->decrypt_ctx, in, len, out, &outlen);
+    if (rc != 0) {
+        SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_update failed during decryption");
+        return;
+    }
+
+    /* MbedTLS caches the last block when decrypting with cbc.
+     * By calling finish the block is flushed to out, however the unprocessed
+     * data counter is not reset.
+     * Calling mbedtls_cipher_reset resets the unprocessed data counter.
+     */
+    if (outlen == 0) {
+        rc = mbedtls_cipher_finish(&cipher->decrypt_ctx, out, &outlen);
+    } else if (outlen == len) {
+        return;
+    } else {
+        rc = mbedtls_cipher_finish(&cipher->decrypt_ctx, (unsigned char *) out +
+                outlen , &outlen);
+    }
+
+    if (rc != 0) {
+        SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_finish failed during decryption");
+        return;
+    }
+
+    rc = mbedtls_cipher_reset(&cipher->decrypt_ctx);
+
+    if (rc != 0) {
+        SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_reset failed during decryption");
+        return;
+    }
+
+    if (outlen != len) {
+        SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_update: output size %zu for %zu",
+                outlen, len);
+        return;
+    }
+
+}
+
+static void cipher_cleanup(struct ssh_cipher_struct *cipher)
+{
+    mbedtls_cipher_free(&cipher->encrypt_ctx);
+    mbedtls_cipher_free(&cipher->decrypt_ctx);
+}
+
+static int des3_set_encrypt_key(struct ssh_cipher_struct *cipher, void *key,
+        void *IV)
+{
+    const mbedtls_cipher_info_t *cipher_info;
+    unsigned char *des3_key = NULL;
+    size_t des_key_size = 0;
+    int rc;
+
+    mbedtls_cipher_init(&cipher->encrypt_ctx);
+    cipher_info = mbedtls_cipher_info_from_type(cipher->type);
+
+    rc = mbedtls_cipher_setup(&cipher->encrypt_ctx, cipher_info);
+    if (rc != 0) {
+        SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setup failed");
+        goto error;
+    }
+
+    des3_key = malloc(cipher_info->key_bitlen / 8);
+    if (des3_key == NULL) {
+        SSH_LOG(SSH_LOG_WARNING, "error allocating memory for key");
+        goto error;
+    }
+
+    des_key_size = cipher_info->key_bitlen / (8 * 3);
+    memcpy(des3_key, key, des_key_size);
+    memcpy(des3_key + des_key_size, (unsigned char * )key + des_key_size,
+            des_key_size);
+    memcpy(des3_key + 2 * des_key_size,
+            (unsigned char *) key + 2 * des_key_size, des_key_size);
+
+    rc = mbedtls_cipher_setkey(&cipher->encrypt_ctx, des3_key,
+                               cipher_info->key_bitlen,
+                               MBEDTLS_ENCRYPT);
+    if (rc != 0) {
+        SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setkey failed");
+        goto error;
+    }
+
+    rc = mbedtls_cipher_set_iv(&cipher->encrypt_ctx, IV, cipher_info->iv_size);
+
+    if (rc != 0) {
+        SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_set_iv failed");
+        goto error;
+    }
+
+    rc = mbedtls_cipher_reset(&cipher->encrypt_ctx);
+
+    if (rc != 0) {
+        SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_reset failed");
+        goto error;
+    }
+
+    SAFE_FREE(des3_key);
+    return SSH_OK;
+error:
+    mbedtls_cipher_free(&cipher->encrypt_ctx);
+    if (des3_key != NULL) {
+        SAFE_FREE(des3_key);
+    }
+    return SSH_ERROR;
+}
+
+static int des3_set_decrypt_key(struct ssh_cipher_struct *cipher, void *key,
+        void *IV)
+{
+    const mbedtls_cipher_info_t *cipher_info;
+    unsigned char *des3_key = NULL;
+    size_t des_key_size = 0;
+    int rc;
+
+    mbedtls_cipher_init(&cipher->decrypt_ctx);
+    cipher_info = mbedtls_cipher_info_from_type(cipher->type);
+
+    rc = mbedtls_cipher_setup(&cipher->decrypt_ctx, cipher_info);
+    if (rc != 0) {
+        SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setup failed");
+        goto error;
+    }
+
+    des3_key = malloc(cipher_info->key_bitlen / 8);
+    if (des3_key == NULL) {
+        SSH_LOG(SSH_LOG_WARNING, "error allocating memory for key");
+        goto error;
+    }
+
+    des_key_size = cipher_info->key_bitlen / (8 * 3);
+    memcpy(des3_key, key, des_key_size);
+    memcpy(des3_key + des_key_size, (unsigned char *) key + des_key_size,
+            des_key_size);
+    memcpy(des3_key + 2 * des_key_size,
+            (unsigned char *) key + 2 * des_key_size,
+            des_key_size);
+
+    rc = mbedtls_cipher_setkey(&cipher->decrypt_ctx, des3_key,
+                               cipher_info->key_bitlen,
+                               MBEDTLS_DECRYPT);
+    if (rc != 0) {
+        SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setkey failed");
+        goto error;
+    }
+
+    rc = mbedtls_cipher_set_iv(&cipher->decrypt_ctx, IV, cipher_info->iv_size);
+
+    if (rc != 0) {
+        SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_set_iv failed");
+        goto error;
+    }
+
+    rc = mbedtls_cipher_reset(&cipher->decrypt_ctx);
+
+    if (rc != 0) {
+        SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_reset failed");
+        goto error;
+    }
+
+    SAFE_FREE(des3_key);
+    return SSH_OK;
+error:
+    mbedtls_cipher_free(&cipher->decrypt_ctx);
+    if (des3_key != NULL) {
+        SAFE_FREE(des3_key);
+    }
+    return SSH_ERROR;
+}
+
+static struct ssh_cipher_struct ssh_ciphertab[] = {
+    {
+        .name = "blowfish-cbc",
+        .blocksize = 8,
+        .keysize = 128,
+        .type = MBEDTLS_CIPHER_BLOWFISH_CBC,
+        .set_encrypt_key = cipher_set_encrypt_key_cbc,
+        .set_decrypt_key = cipher_set_decrypt_key_cbc,
+        .encrypt = cipher_encrypt_cbc,
+        .decrypt = cipher_decrypt_cbc,
+        .cleanup = cipher_cleanup
+    },
+    {
+        .name = "aes128-ctr",
+        .blocksize = 16,
+        .keysize = 128,
+        .type = MBEDTLS_CIPHER_AES_128_CTR,
+        .set_encrypt_key = cipher_set_encrypt_key,
+        .set_decrypt_key = cipher_set_decrypt_key,
+        .encrypt = cipher_encrypt,
+        .decrypt = cipher_decrypt,
+        .cleanup = cipher_cleanup
+    },
+    {
+        .name = "aes192-ctr",
+        .blocksize = 16,
+        .keysize = 192,
+        .type = MBEDTLS_CIPHER_AES_192_CTR,
+        .set_encrypt_key = cipher_set_encrypt_key,
+        .set_decrypt_key = cipher_set_decrypt_key,
+        .encrypt = cipher_encrypt,
+        .decrypt = cipher_decrypt,
+        .cleanup = cipher_cleanup
+    },
+    {
+        .name = "aes256-ctr",
+        .blocksize = 16,
+        .keysize = 256,
+        .type = MBEDTLS_CIPHER_AES_256_CTR,
+        .set_encrypt_key = cipher_set_encrypt_key,
+        .set_decrypt_key = cipher_set_decrypt_key,
+        .encrypt = cipher_encrypt,
+        .decrypt = cipher_decrypt,
+        .cleanup = cipher_cleanup
+    },
+    {
+        .name = "aes128-cbc",
+        .blocksize = 16,
+        .keysize = 128,
+        .type = MBEDTLS_CIPHER_AES_128_CBC,
+        .set_encrypt_key = cipher_set_encrypt_key_cbc,
+        .set_decrypt_key = cipher_set_decrypt_key_cbc,
+        .encrypt = cipher_encrypt_cbc,
+        .decrypt = cipher_decrypt_cbc,
+        .cleanup = cipher_cleanup
+    },
+    {
+        .name = "aes192-cbc",
+        .blocksize = 16,
+        .keysize = 192,
+        .type = MBEDTLS_CIPHER_AES_192_CBC,
+        .set_encrypt_key = cipher_set_encrypt_key_cbc,
+        .set_decrypt_key = cipher_set_decrypt_key_cbc,
+        .encrypt = cipher_encrypt_cbc,
+        .decrypt = cipher_decrypt_cbc,
+        .cleanup = cipher_cleanup
+    },
+    {
+        .name = "aes256-cbc",
+        .blocksize = 16,
+        .keysize = 256,
+        .type = MBEDTLS_CIPHER_AES_256_CBC,
+        .set_encrypt_key = cipher_set_encrypt_key_cbc,
+        .set_decrypt_key = cipher_set_decrypt_key_cbc,
+        .encrypt = cipher_encrypt_cbc,
+        .decrypt = cipher_decrypt_cbc,
+        .cleanup = cipher_cleanup
+    },
+    {
+        .name = "3des-cbc",
+        .blocksize = 8,
+        .keysize = 192,
+        .type = MBEDTLS_CIPHER_DES_EDE3_CBC,
+        .set_encrypt_key = cipher_set_encrypt_key_cbc,
+        .set_decrypt_key = cipher_set_decrypt_key_cbc,
+        .encrypt = cipher_encrypt_cbc,
+        .decrypt = cipher_decrypt_cbc,
+        .cleanup = cipher_cleanup
+    },
+    {
+        .name = "3des-cbc-ssh1",
+        .blocksize = 8,
+        .keysize = 192,
+        .type = MBEDTLS_CIPHER_DES_CBC,
+        .set_encrypt_key = des3_set_encrypt_key,
+        .set_decrypt_key = des3_set_decrypt_key,
+        .encrypt = cipher_encrypt_cbc,
+        .decrypt = cipher_decrypt_cbc,
+        .cleanup = cipher_cleanup
+    },
+    {
+        .name = "des-cbc-ssh1",
+        .blocksize = 8,
+        .keysize = 64,
+        .type = MBEDTLS_CIPHER_DES_CBC,
+        .set_encrypt_key = cipher_set_encrypt_key_cbc,
+        .set_decrypt_key = cipher_set_decrypt_key_cbc,
+        .encrypt = cipher_encrypt_cbc,
+        .decrypt = cipher_decrypt_cbc,
+    },
+    {
+        .name = NULL,
+        .blocksize = 0,
+        .keysize = 0,
+        .set_encrypt_key = NULL,
+        .set_decrypt_key = NULL,
+        .encrypt = NULL,
+        .decrypt = NULL,
+        .cleanup = NULL
+    }
+};
+
+struct ssh_cipher_struct *ssh_get_ciphertab(void)
+{
+    return ssh_ciphertab;
+}
+
+void ssh_mbedtls_init(void)
+{
+    int rc;
+
+    mbedtls_entropy_init(&ssh_mbedtls_entropy);
+    mbedtls_ctr_drbg_init(&ssh_mbedtls_ctr_drbg);
+
+    rc = mbedtls_ctr_drbg_seed(&ssh_mbedtls_ctr_drbg, mbedtls_entropy_func,
+            &ssh_mbedtls_entropy, NULL, 0);
+    if (rc != 0) {
+        mbedtls_ctr_drbg_free(&ssh_mbedtls_ctr_drbg);
+    }
+}
+
+int ssh_mbedtls_random(void *where, int len, int strong)
+{
+    int rc = 0;
+    if (strong) {
+        mbedtls_ctr_drbg_set_prediction_resistance(&ssh_mbedtls_ctr_drbg,
+                MBEDTLS_CTR_DRBG_PR_ON);
+        rc = mbedtls_ctr_drbg_random(&ssh_mbedtls_ctr_drbg, where, len);
+        mbedtls_ctr_drbg_set_prediction_resistance(&ssh_mbedtls_ctr_drbg,
+                MBEDTLS_CTR_DRBG_PR_OFF);
+    } else {
+        rc = mbedtls_ctr_drbg_random(&ssh_mbedtls_ctr_drbg, where, len);
+    }
+
+    return !rc;
+}
+
+void ssh_mbedtls_cleanup(void)
+{
+    mbedtls_ctr_drbg_free(&ssh_mbedtls_ctr_drbg);
+    mbedtls_entropy_free(&ssh_mbedtls_entropy);
+}
+
+#endif /* HAVE_LIBMBEDCRYPTO */
diff --git a/src/mbedcrypto_missing.c b/src/mbedcrypto_missing.c
new file mode 100644
index 00000000..ceb404b2
--- /dev/null
+++ b/src/mbedcrypto_missing.c
@@ -0,0 +1,126 @@
+/*
+ * This file is part of the SSH Library
+ *
+ * Copyright (c) 2017 Sartura d.o.o.
+ *
+ * Author: Juraj Vijtiuk <juraj.vijtiuk@xxxxxxxxxx>
+ *
+ * The SSH Library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ *
+ * The SSH Library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the SSH Library; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#include "libssh/priv.h"
+#include "libssh/libmbedcrypto.h"
+
+#ifdef HAVE_LIBMBEDCRYPTO
+bignum ssh_mbedcry_bn_new(void)
+{
+    bignum bn;
+
+    bn = malloc(sizeof(mbedtls_mpi));
+    if (bn) {
+        mbedtls_mpi_init(bn);
+    }
+
+    return bn;
+}
+
+void ssh_mbedcry_bn_free(bignum bn)
+{
+    mbedtls_mpi_free(bn);
+    SAFE_FREE(bn);
+}
+
+char *ssh_mbedcry_bn2num(bignum num, int radix)
+{
+    char *buf = NULL;
+    size_t olen;
+    int rc;
+
+    rc = mbedtls_mpi_write_string(num, radix, buf, 0, &olen);
+    if (rc != 0) {
+        return NULL;
+    }
+
+    buf = malloc(olen);
+    if (!buf) {
+        return NULL;
+    }
+
+    rc = mbedtls_mpi_write_string(num, radix, buf, olen, &olen);
+    if (rc != 0) {
+        SAFE_FREE(buf);
+        return NULL;
+    }
+
+    return buf;
+}
+
+int ssh_mbedcry_rand(bignum rnd, int bits, int top, int bottom)
+{
+    size_t len;
+    int rc;
+    int i;
+
+    if (bits <= 0) {
+        return 0;
+    }
+
+    len = bits / 8 + 1;
+    rc = mbedtls_mpi_fill_random(rnd, len, mbedtls_ctr_drbg_random,
+            &ssh_mbedtls_ctr_drbg);
+    if (rc != 0) {
+        return 0;
+    }
+
+    for (i = len * 8 - 1; i >= bits; i--) {
+        rc = mbedtls_mpi_set_bit(rnd, i, 0);
+        if (rc != 0) {
+            return 0;
+        }
+    }
+
+    if (top == 0) {
+        rc = mbedtls_mpi_set_bit(rnd, bits - 1, 0);
+    }
+
+    if (top == 1) {
+        if (bits < 2) {
+            return 0;
+        }
+
+        rc = mbedtls_mpi_set_bit(rnd, bits - 2, 0);
+        if (rc != 0) {
+            return 0;
+        }
+    }
+
+    if (bottom) {
+        rc = mbedtls_mpi_set_bit(rnd, 0, 1);
+        if (rc != 0) {
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
+int ssh_mbedcry_is_bit_set(bignum num, size_t pos)
+{
+    int bit;
+    bit = mbedtls_mpi_get_bit(num, pos);
+    return bit;
+}
+#endif
diff --git a/src/misc.c b/src/misc.c
index 1e09a25d..ad560bda 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -35,6 +35,7 @@
 
 #endif /* _WIN32 */
 
+#include <errno.h>
 #include <limits.h>
 #include <stdio.h>
 #include <string.h>
@@ -81,6 +82,12 @@
 #define CRYPTO_STRING ""
 #endif
 
+#ifdef HAVE_LIBMBEDCRYPTO
+#define MBED_STRING "/mbedtls"
+#else
+#define MBED_STRING ""
+#endif
+
 #ifdef WITH_ZLIB
 #define ZLIB_STRING "/zlib"
 #else
@@ -348,7 +355,7 @@ char *ssh_hostport(const char *host, int port){
  */
 const char *ssh_version(int req_version) {
   if (req_version <= LIBSSH_VERSION_INT) {
-    return SSH_STRINGIFY(LIBSSH_VERSION) GCRYPT_STRING CRYPTO_STRING
+    return SSH_STRINGIFY(LIBSSH_VERSION) GCRYPT_STRING CRYPTO_STRING MBED_STRING
       ZLIB_STRING;
   }
 
@@ -780,8 +787,7 @@ char *ssh_path_expand_escape(ssh_session session, const char *s) {
 /**
  * @internal
  *
- * @brief Analyze the SSH banner to find out if we have a SSHv1 or SSHv2
- * server.
+ * @brief Analyze the SSH banner to extract version information.
  *
  * @param  session      The session to analyze the banner from.
  * @param  server       0 means we are a client, 1 a server.
@@ -790,7 +796,7 @@ char *ssh_path_expand_escape(ssh_session session, const char *s) {
  *
  * @return 0 on success, < 0 on error.
  *
- * @see ssh_get_banner()
+ * @see ssh_get_issue_banner()
  */
 int ssh_analyze_banner(ssh_session session, int server, int *ssh1, int *ssh2) {
     const char *banner;
@@ -824,7 +830,7 @@ int ssh_analyze_banner(ssh_session session, int server, int *ssh1, int *ssh2) {
 
     SSH_LOG(SSH_LOG_RARE, "Analyzing banner: %s", banner);
 
-  switch(banner[4]) {
+    switch (banner[4]) {
         case '1':
             *ssh1 = 1;
             if (strlen(banner) > 6) {
@@ -844,9 +850,12 @@ int ssh_analyze_banner(ssh_session session, int server, int *ssh1, int *ssh2) {
             return -1;
     }
 
+    /* Make a best-effort to extract OpenSSH version numbers. */
     openssh = strstr(banner, "OpenSSH");
     if (openssh != NULL) {
-      unsigned int major, minor;
+        char *tmp = NULL;
+        unsigned long int major = 0UL;
+        unsigned long int minor = 0UL;
 
         /*
          * The banner is typical:
@@ -854,30 +863,33 @@ int ssh_analyze_banner(ssh_session session, int server, int *ssh1, int *ssh2) {
          * 012345678901234567890
          */
         if (strlen(openssh) > 9) {
-          major = strtoul(openssh + 8, (char **) NULL, 10);
-          if (major < 1 || major > 100) {
-              ssh_set_error(session,
-                            SSH_FATAL,
-                            "Invalid major version number: %s",
-                            banner);
-              return -1;
+            major = strtoul(openssh + 8, &tmp, 10);
+            if ((tmp == (openssh + 8)) ||
+                ((errno == ERANGE) && (major == ULONG_MAX)) ||
+                ((errno != 0) && (major == 0)) ||
+                ((major < 1) || (major > 100))) {
+                /* invalid major */
+                goto done;
             }
-          minor = strtoul(openssh + 10, (char **) NULL, 10);
-          if (minor > 100) {
-              ssh_set_error(session,
-                            SSH_FATAL,
-                            "Invalid minor version number: %s",
-                            banner);
-              return -1;
+
+            minor = strtoul(openssh + 10, &tmp, 10);
+            if ((tmp == (openssh + 10)) ||
+                ((errno == ERANGE) && (major == ULONG_MAX)) ||
+                ((errno != 0) && (major == 0)) ||
+                (minor > 100)) {
+                /* invalid minor */
+                goto done;
             }
-          session->openssh = SSH_VERSION_INT(major, minor, 0);
+
+            session->openssh = SSH_VERSION_INT(((int) major), ((int) minor), 0);
+
             SSH_LOG(SSH_LOG_RARE,
-                  "We are talking to an OpenSSH client version: %d.%d (%x)",
+                    "We are talking to an OpenSSH client version: %lu.%lu (%x)",
                     major, minor, session->openssh);
         }
     }
 
-
+done:
     return 0;
 }
 
diff --git a/src/options.c b/src/options.c
index 68c11053..e73f7529 100644
--- a/src/options.c
+++ b/src/options.c
@@ -1031,7 +1031,9 @@ int ssh_options_getopt(ssh_session session, int *argcptr, char **argv) {
   int argc = *argcptr;
   int debuglevel = 0;
   int usersa = 0;
+#ifdef HAVE_DSA
   int usedss = 0;
+#endif
   int compress = 0;
   int cont = 1;
   int current = 0;
@@ -1063,9 +1065,11 @@ int ssh_options_getopt(ssh_session session, int *argcptr, char **argv) {
       case 'r':
         usersa++;
         break;
+#ifdef HAVE_DSA
       case 'd':
         usedss++;
         break;
+#endif
       case 'c':
         cipher = optarg;
         break;
@@ -1128,7 +1132,11 @@ int ssh_options_getopt(ssh_session session, int *argcptr, char **argv) {
       optind++;
   }
 
-  if (usersa && usedss) {
+  if (usersa
+#ifdef HAVE_DSA
+          && usedss
+#endif
+          ) {
     ssh_set_error(session, SSH_FATAL, "Either RSA or DSS must be chosen");
     cont = 0;
   }
@@ -1426,10 +1434,12 @@ int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type,
           }
           key_type = ssh_key_type(key);
           switch (key_type) {
+#ifdef HAVE_DSA
           case SSH_KEYTYPE_DSS:
               bind_key_loc = &sshbind->dsa;
               bind_key_path_loc = &sshbind->dsakey;
               break;
+#endif
           case SSH_KEYTYPE_ECDSA:
 #ifdef HAVE_ECC
               bind_key_loc = &sshbind->ecdsa;
@@ -1483,9 +1493,11 @@ int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type,
 
             key_type = ssh_key_type(key);
             switch (key_type) {
+#ifdef HAVE_DSA
                 case SSH_KEYTYPE_DSS:
                     bind_key_loc = &sshbind->dsa;
                     break;
+#endif
                 case SSH_KEYTYPE_ECDSA:
 #ifdef HAVE_ECC
                     bind_key_loc = &sshbind->ecdsa;
@@ -1581,12 +1593,14 @@ int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type,
         ssh_set_log_level(i & 0xffff);
       }
       break;
+#ifdef HAVE_DSA
     case SSH_BIND_OPTIONS_DSAKEY:
         rc = ssh_bind_set_key(sshbind, &sshbind->dsakey, value);
         if (rc < 0) {
             return -1;
         }
         break;
+#endif
     case SSH_BIND_OPTIONS_RSAKEY:
         rc = ssh_bind_set_key(sshbind, &sshbind->rsakey, value);
         if (rc < 0) {
diff --git a/src/pki.c b/src/pki.c
index 91f972b1..94720d98 100644
--- a/src/pki.c
+++ b/src/pki.c
@@ -65,9 +65,11 @@
 #include "libssh/agent.h"
 
 enum ssh_keytypes_e pki_privatekey_type_from_string(const char *privkey) {
+#ifdef HAVE_DSA
     if (strncmp(privkey, DSA_HEADER_BEGIN, strlen(DSA_HEADER_BEGIN)) == 0) {
         return SSH_KEYTYPE_DSS;
     }
+#endif
 
     if (strncmp(privkey, RSA_HEADER_BEGIN, strlen(RSA_HEADER_BEGIN)) == 0) {
         return SSH_KEYTYPE_RSA;
@@ -138,6 +140,16 @@ void ssh_key_clean (ssh_key key){
 #ifdef HAVE_OPENSSL_ECC
     if(key->ecdsa) EC_KEY_free(key->ecdsa);
 #endif /* HAVE_OPENSSL_ECC */
+#elif defined HAVE_LIBMBEDCRYPTO
+    if (key->rsa != NULL) {
+        mbedtls_pk_free(key->rsa);
+        SAFE_FREE(key->rsa);
+    }
+
+    if (key->ecdsa != NULL) {
+        mbedtls_ecdsa_free(key->ecdsa);
+        SAFE_FREE(key->ecdsa);
+    }
 #endif
     if (key->ed25519_privkey != NULL){
         BURN_BUFFER(key->ed25519_privkey, sizeof(ed25519_privkey));
@@ -152,7 +164,9 @@ void ssh_key_clean (ssh_key key){
     key->type=SSH_KEYTYPE_UNKNOWN;
     key->ecdsa_nid = 0;
     key->type_c=NULL;
+#ifdef HAVE_DSA
     key->dsa = NULL;
+#endif
     key->rsa = NULL;
     key->ecdsa = NULL;
 }
@@ -190,8 +204,10 @@ enum ssh_keytypes_e ssh_key_type(const ssh_key key){
  */
 const char *ssh_key_type_to_char(enum ssh_keytypes_e type) {
   switch (type) {
+#ifdef HAVE_DSA
     case SSH_KEYTYPE_DSS:
       return "ssh-dss";
+#endif
     case SSH_KEYTYPE_RSA:
       return "ssh-rsa";
     case SSH_KEYTYPE_RSA1:
@@ -200,8 +216,10 @@ const char *ssh_key_type_to_char(enum ssh_keytypes_e type) {
       return "ssh-ecdsa";
     case SSH_KEYTYPE_ED25519:
       return "ssh-ed25519";
+#ifdef HAVE_DSA
     case SSH_KEYTYPE_DSS_CERT01:
       return "ssh-dss-cert-v01@xxxxxxxxxxx";
+#endif
     case SSH_KEYTYPE_RSA_CERT01:
       return "ssh-rsa-cert-v01@xxxxxxxxxxx";
     case SSH_KEYTYPE_UNKNOWN:
@@ -228,14 +246,18 @@ enum ssh_keytypes_e ssh_key_type_from_name(const char *name) {
         return SSH_KEYTYPE_RSA1;
     } else if (strcmp(name, "rsa") == 0) {
         return SSH_KEYTYPE_RSA;
+#ifdef HAVE_DSA
     } else if (strcmp(name, "dsa") == 0) {
         return SSH_KEYTYPE_DSS;
+#endif
     } else if (strcmp(name, "ssh-rsa1") == 0) {
         return SSH_KEYTYPE_RSA1;
     } else if (strcmp(name, "ssh-rsa") == 0) {
         return SSH_KEYTYPE_RSA;
+#ifdef HAVE_DSA
     } else if (strcmp(name, "ssh-dss") == 0) {
         return SSH_KEYTYPE_DSS;
+#endif
     } else if (strcmp(name, "ssh-ecdsa") == 0
             || strcmp(name, "ecdsa") == 0
             || strcmp(name, "ecdsa-sha2-nistp256") == 0
@@ -244,8 +266,10 @@ enum ssh_keytypes_e ssh_key_type_from_name(const char *name) {
         return SSH_KEYTYPE_ECDSA;
     } else if (strcmp(name, "ssh-ed25519") == 0){
         return SSH_KEYTYPE_ED25519;
+#ifdef HAVE_DSA
     } else if (strcmp(name, "ssh-dss-cert-v01@xxxxxxxxxxx") == 0) {
         return SSH_KEYTYPE_DSS_CERT01;
+#endif
     } else if (strcmp(name, "ssh-rsa-cert-v01@xxxxxxxxxxx") == 0) {
         return SSH_KEYTYPE_RSA_CERT01;
     }
@@ -341,6 +365,7 @@ void ssh_signature_free(ssh_signature sig)
     }
 
     switch(sig->type) {
+#ifdef HAVE_DSA
         case SSH_KEYTYPE_DSS:
 #ifdef HAVE_LIBGCRYPT
             gcry_sexp_release(sig->dsa_sig);
@@ -348,12 +373,15 @@ void ssh_signature_free(ssh_signature sig)
             DSA_SIG_free(sig->dsa_sig);
 #endif
             break;
+#endif
         case SSH_KEYTYPE_RSA:
         case SSH_KEYTYPE_RSA1:
 #ifdef HAVE_LIBGCRYPT
             gcry_sexp_release(sig->rsa_sig);
 #elif defined HAVE_LIBCRYPTO
             SAFE_FREE(sig->rsa_sig);
+#elif defined HAVE_LIBMBEDCRYPTO
+            SAFE_FREE(sig->rsa_sig);
 #endif
             break;
         case SSH_KEYTYPE_ECDSA:
@@ -361,12 +389,17 @@ void ssh_signature_free(ssh_signature sig)
             gcry_sexp_release(sig->ecdsa_sig);
 #elif defined(HAVE_LIBCRYPTO) && defined(HAVE_OPENSSL_ECC)
             ECDSA_SIG_free(sig->ecdsa_sig);
+#elif defined HAVE_LIBMBEDCRYPTO
+            bignum_free(sig->ecdsa_sig.r);
+            bignum_free(sig->ecdsa_sig.s);
 #endif
             break;
         case SSH_KEYTYPE_ED25519:
             SAFE_FREE(sig->ed25519_sig);
             break;
+#ifdef HAVE_DSA
         case SSH_KEYTYPE_DSS_CERT01:
+#endif
         case SSH_KEYTYPE_RSA_CERT01:
         case SSH_KEYTYPE_UNKNOWN:
             break;
@@ -624,8 +657,10 @@ ssh_public_key ssh_pki_convert_key_to_publickey(const ssh_key key) {
     pub->type = tmp->type;
     pub->type_c = tmp->type_c;
 
+#ifdef HAVE_DSA
     pub->dsa_pub = tmp->dsa;
     tmp->dsa = NULL;
+#endif
     pub->rsa_pub = tmp->rsa;
     tmp->rsa = NULL;
 
@@ -644,7 +679,9 @@ ssh_private_key ssh_pki_convert_key_to_privatekey(const ssh_key key) {
     }
 
     privkey->type = key->type;
+#ifdef HAVE_DSA
     privkey->dsa_priv = key->dsa;
+#endif
     privkey->rsa_priv = key->rsa;
 
     return privkey;
@@ -666,6 +703,7 @@ static int pki_import_pubkey_buffer(ssh_buffer buffer,
     key->flags = SSH_KEY_FLAG_PUBLIC;
 
     switch (type) {
+#ifdef HAVE_DSA
         case SSH_KEYTYPE_DSS:
             {
                 ssh_string p;
@@ -724,6 +762,7 @@ static int pki_import_pubkey_buffer(ssh_buffer buffer,
                 }
             }
             break;
+#endif
         case SSH_KEYTYPE_RSA:
         case SSH_KEYTYPE_RSA1:
             {
@@ -813,8 +852,10 @@ static int pki_import_pubkey_buffer(ssh_buffer buffer,
             ssh_string_free(pubkey);
         }
         break;
+#ifdef HAVE_DSA
         case SSH_KEYTYPE_DSS_CERT01:
         case SSH_KEYTYPE_RSA_CERT01:
+#endif
         case SSH_KEYTYPE_UNKNOWN:
         default:
             SSH_LOG(SSH_LOG_WARN, "Unknown public key protocol %d", type);
@@ -918,8 +959,11 @@ int ssh_pki_import_pubkey_base64(const char *b64_key,
     }
     ssh_string_free(type_s);
 
-    if (type == SSH_KEYTYPE_RSA_CERT01 ||
-        type == SSH_KEYTYPE_DSS_CERT01) {
+    if (type == SSH_KEYTYPE_RSA_CERT01
+#ifdef HAVE_DSA
+        || type == SSH_KEYTYPE_DSS_CERT01
+#endif
+        ) {
         rc = pki_import_cert_buffer(buffer, type, pkey);
     } else {
         rc = pki_import_pubkey_buffer(buffer, type, pkey);
@@ -981,8 +1025,11 @@ int ssh_pki_import_pubkey_blob(const ssh_string key_blob,
     }
     ssh_string_free(type_s);
 
-    if (type == SSH_KEYTYPE_RSA_CERT01 ||
-        type == SSH_KEYTYPE_DSS_CERT01) {
+    if (type == SSH_KEYTYPE_RSA_CERT01
+#ifdef HAVE_DSA
+        || type == SSH_KEYTYPE_DSS_CERT01
+#endif
+        ) {
         rc = pki_import_cert_buffer(buffer, type, pkey);
     } else {
         rc = pki_import_pubkey_buffer(buffer, type, pkey);
@@ -1181,11 +1228,13 @@ int ssh_pki_generate(enum ssh_keytypes_e type, int parameter,
             if(rc == SSH_ERROR)
                 goto error;
             break;
+#ifdef HAVE_DSA
         case SSH_KEYTYPE_DSS:
             rc = pki_key_generate_dss(key, parameter);
             if(rc == SSH_ERROR)
                 goto error;
             break;
+#endif
         case SSH_KEYTYPE_ECDSA:
 #ifdef HAVE_ECC
             rc = pki_key_generate_ecdsa(key, parameter);
@@ -1203,7 +1252,9 @@ int ssh_pki_generate(enum ssh_keytypes_e type, int parameter,
                 goto error;
             }
             break;
+#ifdef HAVE_DSA
         case SSH_KEYTYPE_DSS_CERT01:
+#endif
         case SSH_KEYTYPE_RSA_CERT01:
         case SSH_KEYTYPE_UNKNOWN:
             goto error;
@@ -1581,9 +1632,13 @@ int ssh_pki_signature_verify_blob(ssh_session session,
 
         sha1(digest, dlen, hash);
 #ifdef DEBUG_CRYPTO
-        ssh_print_hexa(key->type == SSH_KEYTYPE_DSS
+        ssh_print_hexa(
+#ifdef HAVE_DSA
+                       key->type == SSH_KEYTYPE_DSS
                        ? "Hash to be verified with DSA"
-                       : "Hash to be verified with RSA",
+                       :
+#endif
+                       "Hash to be verified with RSA",
                        hash,
                        SHA_DIGEST_LEN);
 #endif
diff --git a/src/pki_container_openssh.c b/src/pki_container_openssh.c
index 551a7f03..33b309c2 100644
--- a/src/pki_container_openssh.c
+++ b/src/pki_container_openssh.c
@@ -113,9 +113,11 @@ static int pki_openssh_import_privkey_blob(ssh_buffer key_blob_buffer,
         SAFE_FREE(privkey);
         SAFE_FREE(pubkey);
         break;
+#ifdef HAVE_DSA
     case SSH_KEYTYPE_DSS_CERT01:
     case SSH_KEYTYPE_DSS:
         /* p,q,g,pub_key,priv_key */
+#endif
     case SSH_KEYTYPE_RSA_CERT01:
     case SSH_KEYTYPE_RSA:
         /* n,e,d,iqmp,p,q */
diff --git a/src/pki_crypto.c b/src/pki_crypto.c
index 70ac6854..40407d65 100644
--- a/src/pki_crypto.c
+++ b/src/pki_crypto.c
@@ -982,6 +982,7 @@ ssh_string pki_publickey_to_blob(const ssh_key key)
     }
 
     switch (key->type) {
+#ifndef HAVE_LIBMBEDCRYPTO
         case SSH_KEYTYPE_DSS: {
             const BIGNUM *bp, *bq, *bg, *bpub_key;
             DSA_get0_pqg(key->dsa, &bp, &bq, &bg);
@@ -1034,6 +1035,7 @@ ssh_string pki_publickey_to_blob(const ssh_key key)
 
             break;
         }
+#endif
         case SSH_KEYTYPE_RSA:
         case SSH_KEYTYPE_RSA1: {
             const BIGNUM *be, *bn;
diff --git a/src/pki_mbedcrypto.c b/src/pki_mbedcrypto.c
new file mode 100644
index 00000000..9ab34a4b
--- /dev/null
+++ b/src/pki_mbedcrypto.c
@@ -0,0 +1,1300 @@
+/*
+<<<<<<< HEAD
+ * This file is part of the SSH Library
+ *
+ * Copyright (c) 2017 Sartura d.o.o.
+ *
+ * Author: Juraj Vijtiuk <juraj.vijtiuk@xxxxxxxxxx>
+ *
+ * The SSH Library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ *
+ * The SSH Library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the SSH Library; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#ifdef HAVE_LIBMBEDCRYPTO
+#include <mbedtls/pk.h>
+#include <mbedtls/error.h>
+
+#include "libssh/priv.h"
+#include "libssh/pki.h"
+#include "libssh/pki_priv.h"
+#include "libssh/buffer.h"
+#include "libssh/bignum.h"
+
+#define MAX_PASSPHRASE_SIZE 1024
+#define MAX_KEY_SIZE 32
+
+ssh_string pki_private_key_to_pem(const ssh_key key, const char *passphrase,
+        ssh_auth_callback auth_fn, void *auth_data)
+{
+    (void) key;
+    (void) passphrase;
+    (void) auth_fn;
+    (void) auth_data; return NULL;
+}
+
+static int pki_key_ecdsa_to_nid(mbedtls_ecdsa_context *ecdsa)
+{
+    mbedtls_ecp_group_id id;
+
+    id = ecdsa->grp.id;
+    if (id == MBEDTLS_ECP_DP_SECP256R1) {
+        return NID_mbedtls_nistp256;
+    } else if (id == MBEDTLS_ECP_DP_SECP384R1) {
+        return NID_mbedtls_nistp384;
+    } else if (id == MBEDTLS_ECP_DP_SECP521R1) {
+        return NID_mbedtls_nistp521;
+    }
+
+    return -1;
+}
+
+ssh_key pki_private_key_from_base64(const char *b64_key, const char *passphrase,
+        ssh_auth_callback auth_fn, void *auth_data)
+{
+    ssh_key key = NULL;
+    mbedtls_pk_context *rsa = NULL;
+    mbedtls_pk_context *ecdsa = NULL;
+    ed25519_privkey *ed25519 = NULL;
+    enum ssh_keytypes_e type;
+    int valid;
+    /* mbedtls pk_parse_key expects strlen to count the 0 byte */
+    size_t b64len = strlen(b64_key) + 1;
+    unsigned char tmp[MAX_PASSPHRASE_SIZE] = {0};
+
+    if (ssh_init() < 0) {
+        return NULL;
+    }
+
+    type = pki_privatekey_type_from_string(b64_key);
+    if (type == SSH_KEYTYPE_UNKNOWN) {
+        SSH_LOG(SSH_LOG_WARN, "Unknown or invalid private key.");
+        return NULL;
+    }
+
+    switch (type) {
+        case SSH_KEYTYPE_RSA:
+        case SSH_KEYTYPE_RSA1:
+            rsa = malloc(sizeof(mbedtls_pk_context));
+            if (rsa == NULL) {
+                return NULL;
+            }
+
+            mbedtls_pk_init(rsa);
+
+            if (passphrase == NULL) {
+                if (auth_fn) {
+                    valid = auth_fn("Passphrase for private key:", (char *) tmp,
+                            MAX_PASSPHRASE_SIZE, 0, 0, auth_data);
+                    if (valid < 0) {
+                        return NULL;
+                    }
+                    /* TODO fix signedness and strlen */
+                    valid = mbedtls_pk_parse_key(rsa,
+                            (const unsigned char *) b64_key,
+                            b64len, tmp,
+                            strnlen((const char *) tmp, MAX_PASSPHRASE_SIZE));
+                } else {
+                    valid = mbedtls_pk_parse_key(rsa,
+                            (const unsigned char *) b64_key,
+                            b64len, NULL,
+                            0);
+                }
+            } else {
+                valid = mbedtls_pk_parse_key(rsa,
+                        (const unsigned char *) b64_key, b64len,
+                        (const unsigned char *) passphrase,
+                        strnlen(passphrase, MAX_PASSPHRASE_SIZE));
+            }
+
+            if (valid != 0) {
+                char error_buf[100];
+                mbedtls_strerror(valid, error_buf, 100);
+                SSH_LOG(SSH_LOG_WARN,"Parsing private key %s", error_buf);
+                goto fail;
+            }
+            break;
+        case SSH_KEYTYPE_ECDSA:
+            ecdsa = malloc(sizeof(mbedtls_pk_context));
+            if (ecdsa == NULL) {
+                return NULL;
+            }
+
+            mbedtls_pk_init(ecdsa);
+
+            if (passphrase == NULL) {
+                if (auth_fn) {
+                    valid = auth_fn("Passphrase for private key:", (char *) tmp,
+                            MAX_PASSPHRASE_SIZE, 0, 0, auth_data);
+                    if (valid < 0) {
+                        return NULL;
+                    }
+                    valid = mbedtls_pk_parse_key(ecdsa,
+                            (const unsigned char *) b64_key,
+                            b64len, tmp,
+                            strnlen((const char *) tmp, MAX_PASSPHRASE_SIZE));
+                } else {
+                    valid = mbedtls_pk_parse_key(ecdsa,
+                            (const unsigned char *) b64_key,
+                            b64len, NULL,
+                            0);
+                }
+            } else {
+                valid = mbedtls_pk_parse_key(ecdsa,
+                        (const unsigned char *) b64_key, b64len,
+                        (const unsigned char *) passphrase,
+                        strnlen(passphrase, MAX_PASSPHRASE_SIZE));
+            }
+
+            if (valid != 0) {
+                char error_buf[100];
+                mbedtls_strerror(valid, error_buf, 100);
+                SSH_LOG(SSH_LOG_WARN,"Parsing private key %s", error_buf);
+                goto fail;
+            }
+            break;
+        case SSH_KEYTYPE_ED25519:
+            /* Cannot open ed25519 keys with libmbedcrypto */
+        default:
+            SSH_LOG(SSH_LOG_WARN, "Unknown or invalid private key type %d",
+                    type);
+            return NULL;
+    }
+
+    key = ssh_key_new();
+    if (key == NULL) {
+        goto fail;
+    }
+
+    key->type = type;
+    key->type_c = ssh_key_type_to_char(type);
+    key->flags = SSH_KEY_FLAG_PRIVATE | SSH_KEY_FLAG_PUBLIC;
+    key->rsa = rsa;
+    if (ecdsa != NULL) {
+        mbedtls_ecp_keypair *keypair = mbedtls_pk_ec(*ecdsa);
+
+        key->ecdsa = malloc(sizeof(mbedtls_ecdsa_context));
+        if (key->ecdsa == NULL) {
+            goto fail;
+        }
+
+        mbedtls_ecdsa_init(key->ecdsa);
+        mbedtls_ecdsa_from_keypair(key->ecdsa, keypair);
+        mbedtls_pk_free(ecdsa);
+        SAFE_FREE(ecdsa);
+    } else {
+        key->ecdsa = NULL;
+    }
+    key->ed25519_privkey = ed25519;
+    rsa = NULL;
+    ecdsa = NULL;
+    if (key->type == SSH_KEYTYPE_ECDSA) {
+        key->ecdsa_nid = pki_key_ecdsa_to_nid(key->ecdsa);
+        key->type_c = pki_key_ecdsa_nid_to_name(key->ecdsa_nid);
+    }
+
+    return key;
+fail:
+    ssh_key_free(key);
+    if (rsa) {
+        mbedtls_pk_free(rsa);
+        SAFE_FREE(rsa);
+    }
+    if (ecdsa) {
+        mbedtls_pk_free(ecdsa);
+        SAFE_FREE(ecdsa);
+    }
+    return NULL;
+}
+
+int pki_pubkey_build_rsa(ssh_key key, ssh_string e, ssh_string n)
+{
+    mbedtls_rsa_context *rsa;
+    const mbedtls_pk_info_t *pk_info;
+    int rc;
+
+    key->rsa = malloc(sizeof(mbedtls_pk_context));
+    if (key->rsa == NULL) {
+        return SSH_ERROR;
+    }
+
+    mbedtls_pk_init(key->rsa);
+    pk_info = mbedtls_pk_info_from_type(MBEDTLS_PK_RSA);
+    mbedtls_pk_setup(key->rsa, pk_info);
+
+    if (mbedtls_pk_can_do(key->rsa, MBEDTLS_PK_RSA)) {
+        rsa = mbedtls_pk_rsa(*key->rsa);
+        rc = mbedtls_mpi_read_binary(&rsa->N, ssh_string_data(n),
+                ssh_string_len(n));
+        if (rc != 0) {
+            return SSH_ERROR;
+        }
+        rc = mbedtls_mpi_read_binary(&rsa->E, ssh_string_data(e),
+                ssh_string_len(e));
+        if (rc != 0) {
+            return SSH_ERROR;
+        }
+
+        rsa->len = (mbedtls_mpi_bitlen(&rsa->N) + 7) >> 3;
+    } else {
+        return SSH_ERROR;
+    }
+
+    return SSH_OK;
+}
+
+ssh_key pki_key_dup(const ssh_key key, int demote)
+{
+    ssh_key new;
+    int rc;
+    const mbedtls_pk_info_t *pk_info;
+
+
+    new = ssh_key_new();
+    if (new == NULL) {
+        return NULL;
+    }
+
+    new->type = key->type;
+    new->type_c = key->type_c;
+    if (demote) {
+        new->flags = SSH_KEY_FLAG_PUBLIC;
+    } else {
+        new->flags = key->flags;
+    }
+
+
+    switch(key->type) {
+        case SSH_KEYTYPE_RSA:
+        case SSH_KEYTYPE_RSA1: {
+            mbedtls_rsa_context *rsa, *new_rsa;
+
+            new->rsa = malloc(sizeof(mbedtls_pk_context));
+            if (new->rsa == NULL) {
+                return NULL;
+            }
+
+            mbedtls_pk_init(new->rsa);
+            pk_info = mbedtls_pk_info_from_type(MBEDTLS_PK_RSA);
+            mbedtls_pk_setup(new->rsa, pk_info);
+
+            if (mbedtls_pk_can_do(key->rsa, MBEDTLS_PK_RSA) &&
+                        mbedtls_pk_can_do(new->rsa, MBEDTLS_PK_RSA)) {
+                rsa = mbedtls_pk_rsa(*key->rsa);
+                new_rsa = mbedtls_pk_rsa(*new->rsa);
+
+                rc = mbedtls_mpi_copy(&new_rsa->N, &rsa->N);
+                if (rc != 0) {
+                    goto fail;
+                }
+
+                rc = mbedtls_mpi_copy(&new_rsa->E, &rsa->E);
+                if (rc != 0) {
+                    goto fail;
+                }
+                new_rsa->len = (mbedtls_mpi_bitlen(&new_rsa->N) + 7) >> 3;
+
+                if (!demote && (key->flags & SSH_KEY_FLAG_PRIVATE)) {
+                    rc = mbedtls_mpi_copy(&new_rsa->D, &rsa->D);
+                    if (rc != 0) {
+                        goto fail;
+                    }
+
+                    rc = mbedtls_mpi_copy(&new_rsa->P, &rsa->P);
+                    if (rc != 0) {
+                        goto fail;
+                    }
+
+                    rc = mbedtls_mpi_copy(&new_rsa->Q, &rsa->Q);
+                    if (rc != 0) {
+                        goto fail;
+                    }
+
+                    rc = mbedtls_mpi_copy(&new_rsa->DP, &rsa->DP);
+                    if (rc != 0) {
+                        goto fail;
+                    }
+
+                    rc = mbedtls_mpi_copy(&new_rsa->DQ, &rsa->DQ);
+                    if (rc != 0) {
+                        goto fail;
+                    }
+
+                    rc = mbedtls_mpi_copy(&new_rsa->QP, &rsa->QP);
+                    if (rc != 0) {
+                        goto fail;
+                    }
+                }
+            } else {
+                goto fail;
+            }
+
+            break;
+        }
+        case SSH_KEYTYPE_ECDSA:
+            new->ecdsa_nid = key->ecdsa_nid;
+
+            new->ecdsa = malloc(sizeof(mbedtls_ecdsa_context));
+
+            if (new->ecdsa == NULL) {
+                return NULL;
+            }
+
+            mbedtls_ecdsa_init(new->ecdsa);
+
+            if (demote && ssh_key_is_private(key)) {
+                rc = mbedtls_ecp_copy(&new->ecdsa->Q, &key->ecdsa->Q);
+                if (rc != 0) {
+                    goto fail;
+                }
+
+                rc = mbedtls_ecp_group_copy(&new->ecdsa->grp, &key->ecdsa->grp);
+                if (rc != 0) {
+                    goto fail;
+                }
+            } else {
+                mbedtls_ecdsa_from_keypair(new->ecdsa, key->ecdsa);
+            }
+
+            break;
+        case SSH_KEYTYPE_ED25519:
+            rc = pki_ed25519_key_dup(new, key);
+            if (rc != SSH_OK) {
+                goto fail;
+            }
+            break;
+        default:
+            ssh_key_free(new);
+            return NULL;
+    }
+
+    return new;
+fail:
+    ssh_key_free(new);
+    return NULL;
+}
+
+int pki_key_generate_rsa(ssh_key key, int parameter)
+{
+    int rc;
+    const mbedtls_pk_info_t *info;
+
+    key->rsa = malloc(sizeof(mbedtls_pk_context));
+    if (key->rsa == NULL) {
+        return SSH_ERROR;
+    }
+
+    mbedtls_pk_init(key->rsa);
+
+    info = mbedtls_pk_info_from_type(MBEDTLS_PK_RSA);
+    rc = mbedtls_pk_setup(key->rsa, info);
+    if (rc != 0) {
+        return SSH_ERROR;
+    }
+
+    if (mbedtls_pk_can_do(key->rsa, MBEDTLS_PK_RSA)) {
+        rc = mbedtls_rsa_gen_key(mbedtls_pk_rsa(*key->rsa), mbedtls_ctr_drbg_random,
+                &ssh_mbedtls_ctr_drbg, parameter, 65537);
+        if (rc != 0) {
+            mbedtls_pk_free(key->rsa);
+            return SSH_ERROR;
+        }
+    }
+
+    return SSH_OK;
+}
+
+int pki_key_compare(const ssh_key k1, const ssh_key k2, enum ssh_keycmp_e what)
+{
+    switch (k1->type) {
+        case SSH_KEYTYPE_RSA:
+        case SSH_KEYTYPE_RSA1: {
+            mbedtls_rsa_context *rsa1, *rsa2;
+            if (mbedtls_pk_can_do(k1->rsa, MBEDTLS_PK_RSA) &&
+                    mbedtls_pk_can_do(k2->rsa, MBEDTLS_PK_RSA)) {
+                if (mbedtls_pk_get_type(k1->rsa) != mbedtls_pk_get_type(k2->rsa) ||
+                        mbedtls_pk_get_bitlen(k1->rsa) !=
+                        mbedtls_pk_get_bitlen(k2->rsa)) {
+                    return 1;
+                }
+
+                rsa1 = mbedtls_pk_rsa(*k1->rsa);
+                rsa2 = mbedtls_pk_rsa(*k2->rsa);
+                if (mbedtls_mpi_cmp_mpi(&rsa1->N, &rsa2->N) != 0) {
+                    return 1;
+                }
+
+                if (mbedtls_mpi_cmp_mpi(&rsa1->E, &rsa2->E) != 0) {
+                    return 1;
+                }
+
+                if (what == SSH_KEY_CMP_PRIVATE) {
+                    if (mbedtls_mpi_cmp_mpi(&rsa1->P, &rsa2->P) != 0) {
+                        return 1;
+                    }
+
+                    if (mbedtls_mpi_cmp_mpi(&rsa1->Q, &rsa2->Q) != 0) {
+                        return 1;
+                    }
+                }
+            }
+            break;
+        }
+        case SSH_KEYTYPE_ECDSA:
+            /* mbedTLS can't compare ecdsa keys */
+                return 1;
+        case SSH_KEYTYPE_ED25519:
+            /* ed25519 keys handled globally */
+            return 0;
+        default:
+            return 1;
+    }
+
+    return 0;
+}
+
+ssh_string make_ecpoint_string(const mbedtls_ecp_group *g, const
+        mbedtls_ecp_point *p)
+{
+    ssh_string s;
+    size_t len = 1;
+    int rc;
+
+    s = ssh_string_new(len);
+    if (s == NULL) {
+        return NULL;
+    }
+
+    /* mbedtls_ecp_point_write_binary has no way of signaling how big the
+     * destination buffer has to be. Therefore we increase the buffer length
+     * as long as the buffer is too small. */
+    rc = mbedtls_ecp_point_write_binary(g, p, MBEDTLS_ECP_PF_UNCOMPRESSED,
+                &len, ssh_string_data(s), ssh_string_len(s));
+    while (rc == MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL) {
+        ssh_string_free(s);
+        len *= 2;
+
+        s = ssh_string_new(len);
+        if (s == NULL) {
+            return NULL;
+        }
+
+        rc = mbedtls_ecp_point_write_binary(g, p, MBEDTLS_ECP_PF_UNCOMPRESSED,
+                &len, ssh_string_data(s), ssh_string_len(s));
+    }
+
+    if (rc == MBEDTLS_ERR_ECP_BAD_INPUT_DATA) {
+        ssh_string_free(s);
+        return NULL;
+    }
+
+    ssh_string_free(s);
+    s = ssh_string_new(len);
+    if (s == NULL) {
+        return NULL;
+    }
+
+    rc = mbedtls_ecp_point_write_binary(g, p, MBEDTLS_ECP_PF_UNCOMPRESSED,
+                &len, ssh_string_data(s), ssh_string_len(s));
+
+    if (rc != 0) {
+        ssh_string_free(s);
+        return NULL;
+    }
+
+    if (len != ssh_string_len(s)) {
+        ssh_string_free(s);
+        return NULL;
+    }
+
+    return s;
+}
+
+static const char* pki_key_ecdsa_nid_to_char(int nid)
+{
+    switch (nid) {
+        case NID_mbedtls_nistp256:
+            return "nistp256";
+        case NID_mbedtls_nistp384:
+            return "nistp384";
+        case NID_mbedtls_nistp521:
+            return "nistp521";
+        default:
+            break;
+    }
+
+    return "unknown";
+}
+
+ssh_string pki_publickey_to_blob(const ssh_key key)
+{
+    ssh_buffer buffer;
+    ssh_string type_s;
+    ssh_string e = NULL;
+    ssh_string n = NULL;
+    ssh_string str = NULL;
+    int rc;
+
+    buffer = ssh_buffer_new();
+    if (buffer == NULL) {
+        return NULL;
+    }
+
+    if (key->cert != NULL) {
+        rc = ssh_buffer_add_buffer(buffer, key->cert);
+        if (rc < 0) {
+            ssh_buffer_free(buffer);
+            return NULL;
+        }
+
+        goto makestring;
+    }
+
+    type_s = ssh_string_from_char(key->type_c);
+    if (type_s == NULL) {
+        ssh_buffer_free(buffer);
+        return NULL;
+    }
+
+    rc = ssh_buffer_add_ssh_string(buffer, type_s);
+    ssh_string_free(type_s);
+    if (rc < 0) {
+        ssh_buffer_free(buffer);
+        return NULL;
+    }
+
+    switch (key->type) {
+        case SSH_KEYTYPE_RSA:
+        case SSH_KEYTYPE_RSA1: {
+            mbedtls_rsa_context *rsa;
+            if (mbedtls_pk_can_do(key->rsa, MBEDTLS_PK_RSA) == 0) {
+                ssh_buffer_free(buffer);
+                return NULL;
+            }
+
+            rsa = mbedtls_pk_rsa(*key->rsa);
+
+            e = ssh_make_bignum_string(&rsa->E);
+            if (e == NULL) {
+                goto fail;
+            }
+
+            n = ssh_make_bignum_string(&rsa->N);
+            if (n == NULL) {
+                goto fail;
+            }
+
+            if (ssh_buffer_add_ssh_string(buffer, e) < 0) {
+                goto fail;
+            }
+
+            if (ssh_buffer_add_ssh_string(buffer, n) < 0) {
+                goto fail;
+            }
+
+            ssh_string_burn(e);
+            ssh_string_free(e);
+            e = NULL;
+            ssh_string_burn(n);
+            ssh_string_free(n);
+            n = NULL;
+
+            break;
+        }
+        case SSH_KEYTYPE_ECDSA:
+            rc = ssh_buffer_reinit(buffer);
+            if (rc < 0) {
+                ssh_buffer_free(buffer);
+                return NULL;
+            }
+
+            type_s =
+                ssh_string_from_char(pki_key_ecdsa_nid_to_name(key->ecdsa_nid));
+            if (type_s == NULL) {
+                ssh_buffer_free(buffer);
+                return NULL;
+            }
+
+            rc = ssh_buffer_add_ssh_string(buffer, type_s);
+            ssh_string_free(type_s);
+            if (rc < 0) {
+                ssh_buffer_free(buffer);
+                return NULL;
+            }
+
+            type_s =
+                ssh_string_from_char(pki_key_ecdsa_nid_to_char(key->ecdsa_nid));
+            if (type_s == NULL) {
+                ssh_buffer_free(buffer);
+                return NULL;
+            }
+
+            rc = ssh_buffer_add_ssh_string(buffer, type_s);
+            ssh_string_free(type_s);
+            if (rc < 0) {
+                ssh_buffer_free(buffer);
+                return NULL;
+            }
+
+            e = make_ecpoint_string(&key->ecdsa->grp, &key->ecdsa->Q);
+
+            if (e == NULL) {
+                ssh_buffer_free(buffer);
+                return NULL;
+            }
+
+            rc = ssh_buffer_add_ssh_string(buffer, e);
+            if (rc < 0) {
+                goto fail;
+            }
+
+            ssh_string_burn(e);
+            ssh_string_free(e);
+            e = NULL;
+
+            break;
+        case SSH_KEYTYPE_ED25519:
+            rc = pki_ed25519_public_key_to_blob(buffer, key);
+            if (rc != SSH_OK) {
+                goto fail;
+            }
+            break;
+        default:
+            goto fail;
+    }
+makestring:
+    str = ssh_string_new(ssh_buffer_get_len(buffer));
+    if (str == NULL) {
+        goto fail;
+    }
+
+    rc = ssh_string_fill(str, ssh_buffer_get(buffer),
+            ssh_buffer_get_len(buffer));
+    if (rc < 0) {
+        goto fail;
+    }
+
+    ssh_buffer_free(buffer);
+    return str;
+fail:
+    ssh_buffer_free(buffer);
+    ssh_string_burn(str);
+    ssh_string_free(str);
+    ssh_string_burn(e);
+    ssh_string_free(e);
+    ssh_string_burn(n);
+    ssh_string_free(n);
+
+    return NULL;
+}
+
+int pki_export_pubkey_rsa1(const ssh_key key, const char *host, char *rsa1,
+        size_t rsa1_len)
+{
+    char *e;
+    char *n;
+    int rsa_size = mbedtls_pk_get_bitlen(key->rsa);
+    mbedtls_rsa_context *rsa;
+
+    if (!mbedtls_pk_can_do(key->rsa, MBEDTLS_PK_RSA)) {
+        return SSH_ERROR;
+    }
+
+    rsa = mbedtls_pk_rsa(*key->rsa);
+
+    n = bignum_bn2dec(&rsa->N);
+    if (n == NULL) {
+        return SSH_ERROR;
+    }
+
+    e = bignum_bn2dec(&rsa->E);
+    if (e == NULL) {
+        return SSH_ERROR;
+    }
+
+    snprintf(rsa1, rsa1_len, "%s %d %s %s\n",
+            host, rsa_size << 3, e, n);
+
+    SAFE_FREE(e);
+    SAFE_FREE(n);
+    return SSH_OK;
+}
+
+ssh_string pki_signature_to_blob(const ssh_signature sig)
+{
+    ssh_string sig_blob = NULL;
+
+    switch(sig->type) {
+        case SSH_KEYTYPE_RSA:
+        case SSH_KEYTYPE_RSA1:
+            sig_blob = ssh_string_copy(sig->rsa_sig);
+            break;
+        case SSH_KEYTYPE_ECDSA: {
+            ssh_string r;
+            ssh_string s;
+            ssh_buffer b;
+            int rc;
+
+            b = ssh_buffer_new();
+            if (b == NULL) {
+                return NULL;
+            }
+
+            r = ssh_make_bignum_string(sig->ecdsa_sig.r);
+            if (r == NULL) {
+                ssh_buffer_free(b);
+                return NULL;
+            }
+
+            rc = ssh_buffer_add_ssh_string(b, r);
+            ssh_string_free(r);
+            if (rc < 0) {
+                ssh_buffer_free(b);
+                return NULL;
+            }
+
+            s = ssh_make_bignum_string(sig->ecdsa_sig.s);
+            if (s == NULL) {
+                ssh_buffer_free(b);
+                return NULL;
+            }
+
+            rc = ssh_buffer_add_ssh_string(b, s);
+            ssh_string_free(s);
+            if (rc < 0) {
+                ssh_buffer_free(b);
+                return NULL;
+            }
+
+            sig_blob = ssh_string_new(ssh_buffer_get_len(b));
+            if (sig_blob == NULL) {
+                ssh_buffer_free(b);
+                return NULL;
+            }
+
+            ssh_string_fill(sig_blob, ssh_buffer_get(b), ssh_buffer_get_len(b));
+            ssh_buffer_free(b);
+            break;
+        }
+        case SSH_KEYTYPE_ED25519:
+            sig_blob = pki_ed25519_sig_to_blob(sig);
+            break;
+        default:
+            SSH_LOG(SSH_LOG_WARN, "Unknown signature key type: %s",
+                    sig->type_c);
+            return NULL;
+    }
+
+    return sig_blob;
+}
+
+static ssh_signature pki_signature_from_rsa_blob(const ssh_key pubkey, const
+        ssh_string sig_blob, ssh_signature sig)
+{
+    size_t pad_len = 0;
+    char *blob_orig;
+    char *blob_padded_data;
+    ssh_string sig_blob_padded;
+
+    size_t rsalen = 0;
+    size_t len = ssh_string_len(sig_blob);
+
+    if (pubkey->rsa == NULL) {
+        SSH_LOG(SSH_LOG_WARN, "Pubkey RSA field NULL");
+        goto errout;
+    }
+
+    rsalen = mbedtls_pk_get_bitlen(pubkey->rsa) / 8;
+    if (len > rsalen) {
+        SSH_LOG(SSH_LOG_WARN,
+                "Signature is too big: %lu > %lu",
+                (unsigned long) len,
+                (unsigned long) rsalen);
+        goto errout;
+    }
+#ifdef DEBUG_CRYPTO
+    SSH_LOG(SSH_LOG_WARN, "RSA signature len: %lu", (unsigned long)len);
+    ssh_print_hexa("RSA signature", ssh_string_data(sig_blob), len);
+#endif
+
+    if (len == rsalen) {
+        sig->rsa_sig = ssh_string_copy(sig_blob);
+    } else {
+        SSH_LOG(SSH_LOG_DEBUG, "RSA signature len %lu < %lu",
+                (unsigned long) len,
+                (unsigned long) rsalen);
+        pad_len = rsalen - len;
+
+        sig_blob_padded = ssh_string_new(rsalen);
+        if (sig_blob_padded == NULL) {
+            goto errout;
+        }
+
+        blob_padded_data = (char *) ssh_string_data(sig_blob_padded);
+        blob_orig = (char *) ssh_string_data(sig_blob);
+
+        BURN_BUFFER(blob_padded_data, pad_len);
+        memcpy(blob_padded_data + pad_len, blob_orig, len);
+
+        sig->rsa_sig = sig_blob_padded;
+    }
+
+    return sig;
+
+errout:
+    ssh_signature_free(sig);
+    return NULL;
+}
+ssh_signature pki_signature_from_blob(const ssh_key pubkey, const ssh_string
+        sig_blob, enum ssh_keytypes_e type)
+{
+    ssh_signature sig;
+    int rc;
+
+    sig = ssh_signature_new();
+    if (sig == NULL) {
+        return NULL;
+    }
+
+    sig->type = type;
+    sig->type_c = ssh_key_type_to_char(type);
+
+    switch(type) {
+        case SSH_KEYTYPE_RSA:
+        case SSH_KEYTYPE_RSA1:
+            sig = pki_signature_from_rsa_blob(pubkey, sig_blob, sig);
+            break;
+        case SSH_KEYTYPE_ECDSA: {
+            ssh_buffer b;
+            ssh_string r;
+            ssh_string s;
+            size_t rlen;
+
+            b = ssh_buffer_new();
+            if (b == NULL) {
+                ssh_signature_free(sig);
+                return NULL;
+            }
+
+            rc = ssh_buffer_add_data(b, ssh_string_data(sig_blob),
+                    ssh_string_len(sig_blob));
+
+            if (rc < 0) {
+                ssh_buffer_free(b);
+                ssh_signature_free(sig);
+                return NULL;
+            }
+
+            r = ssh_buffer_get_ssh_string(b);
+            if (r == NULL) {
+                ssh_buffer_free(b);
+                ssh_signature_free(sig);
+                return NULL;
+            }
+#ifdef DEBUG_CRYPTO
+            ssh_print_hexa("r", ssh_string_data(r), ssh_string_len(r));
+#endif
+            sig->ecdsa_sig.r = ssh_make_string_bn(r);
+            ssh_string_burn(r);
+            ssh_string_free(r);
+            if (sig->ecdsa_sig.r == NULL) {
+                ssh_buffer_free(b);
+                ssh_signature_free(sig);
+                return NULL;
+            }
+
+            s = ssh_buffer_get_ssh_string(b);
+            rlen = ssh_buffer_get_len(b);
+            ssh_buffer_free(b);
+            if (s == NULL) {
+                ssh_signature_free(sig);
+                return NULL;
+            }
+
+#ifdef DEBUG_CRYPTO
+            ssh_print_hexa("s", ssh_string_data(s), ssh_string_len(s));
+#endif
+            sig->ecdsa_sig.s = ssh_make_string_bn(s);
+            ssh_string_burn(s);
+            ssh_string_free(s);
+            if (sig->ecdsa_sig.s == NULL) {
+                ssh_signature_free(sig);
+                return NULL;
+            }
+
+            if (rlen != 0) {
+                SSH_LOG(SSH_LOG_WARN, "Signature has remaining bytes in inner "
+                        "sigblob: %lu",
+                        (unsigned long)rlen);
+                ssh_signature_free(sig);
+                return NULL;
+            }
+
+            break;
+        }
+        case SSH_KEYTYPE_ED25519:
+            rc = pki_ed25519_sig_from_blob(sig, sig_blob);
+            if (rc == SSH_ERROR) {
+                ssh_signature_free(sig);
+                return NULL;
+            }
+            break;
+        default:
+            SSH_LOG(SSH_LOG_WARN, "Unknown signature type");
+            return NULL;
+    }
+
+    return sig;
+}
+
+int pki_signature_verify(ssh_session session, const ssh_signature sig, const
+        ssh_key key, const unsigned char *hash, size_t hlen)
+{
+    int rc;
+
+    switch (key->type) {
+        case SSH_KEYTYPE_RSA:
+        case SSH_KEYTYPE_RSA1:
+            rc = mbedtls_pk_verify(key->rsa, MBEDTLS_MD_SHA1, hash, hlen,
+                    ssh_string_data(sig->rsa_sig),
+                    ssh_string_len(sig->rsa_sig));
+            if (rc != 0) {
+                char error_buf[100];
+                mbedtls_strerror(rc, error_buf, 100);
+                ssh_set_error(session, SSH_FATAL, "RSA error: %s", error_buf);
+                return SSH_ERROR;
+            }
+            break;
+        case SSH_KEYTYPE_ECDSA:
+            rc = mbedtls_ecdsa_verify(&key->ecdsa->grp, hash, hlen,
+                    &key->ecdsa->Q, sig->ecdsa_sig.r, sig->ecdsa_sig.s);
+            if (rc != 0) {
+                char error_buf[100];
+                mbedtls_strerror(rc, error_buf, 100);
+                ssh_set_error(session, SSH_FATAL, "RSA error: %s", error_buf);
+                return SSH_ERROR;
+
+            }
+            break;
+        case SSH_KEYTYPE_ED25519:
+            rc = pki_ed25519_verify(key, sig, hash, hlen);
+            if (rc != SSH_OK) {
+                ssh_set_error(session, SSH_FATAL,
+                        "ed25519 signature verification error");
+                return SSH_ERROR;
+            }
+            break;
+        default:
+            ssh_set_error(session, SSH_FATAL, "Unknown public key type");
+            return SSH_ERROR;
+    }
+
+    return SSH_OK;
+}
+
+static ssh_string rsa_do_sign(const unsigned char *digest, int dlen,
+        mbedtls_pk_context *privkey)
+{
+    ssh_string sig_blob;
+    unsigned char *sig;
+    size_t slen;
+    int ok;
+
+    sig = malloc(mbedtls_pk_get_bitlen(privkey) / 8);
+    if (sig == NULL) {
+        return NULL;
+    }
+
+    ok = mbedtls_pk_sign(privkey, MBEDTLS_MD_SHA1, digest, dlen, sig, &slen,
+            mbedtls_ctr_drbg_random, &ssh_mbedtls_ctr_drbg);
+
+    if (ok != 0) {
+        SAFE_FREE(sig);
+        return NULL;
+    }
+
+    sig_blob = ssh_string_new(slen);
+    if (sig_blob == NULL) {
+        SAFE_FREE(sig);
+        return NULL;
+    }
+
+    ssh_string_fill(sig_blob, sig, slen);
+    memset(sig, 'd', slen);
+    SAFE_FREE(sig);
+
+    return sig_blob;
+}
+
+
+ssh_signature pki_do_sign(const ssh_key privkey, const unsigned char *hash,
+        size_t hlen)
+{
+    ssh_signature sig;
+    int rc;
+
+    sig = ssh_signature_new();
+    if (sig == NULL) {
+        return NULL;
+    }
+
+    sig->type = privkey->type;
+    sig->type_c = privkey->type_c;
+
+    switch(privkey->type) {
+        case SSH_KEYTYPE_RSA:
+        case SSH_KEYTYPE_RSA1:
+            sig->rsa_sig = rsa_do_sign(hash, hlen, privkey->rsa);
+            if (sig->rsa_sig == NULL) {
+                ssh_signature_free(sig);
+                return NULL;
+            }
+            break;
+         case SSH_KEYTYPE_ECDSA:
+            sig->ecdsa_sig.r = bignum_new();
+            if (sig->ecdsa_sig.r == NULL) {
+                return NULL;
+            }
+
+            sig->ecdsa_sig.s = bignum_new();
+            if (sig->ecdsa_sig.s == NULL) {
+                bignum_free(sig->ecdsa_sig.r);
+                return NULL;
+            }
+
+            rc = mbedtls_ecdsa_sign(&privkey->ecdsa->grp, sig->ecdsa_sig.r,
+                    sig->ecdsa_sig.s, &privkey->ecdsa->d, hash, hlen,
+                    mbedtls_ctr_drbg_random, &ssh_mbedtls_ctr_drbg);
+            if (rc != 0) {
+                ssh_signature_free(sig);
+                return NULL;
+            }
+            break;
+        case SSH_KEYTYPE_ED25519:
+            rc = pki_ed25519_sign(privkey, sig, hash, hlen);
+            if (rc != SSH_OK) {
+                ssh_signature_free(sig);
+                return NULL;
+            }
+            break;
+        default:
+            ssh_signature_free(sig);
+            return NULL;
+
+    }
+
+    return sig;
+}
+
+#ifdef WITH_SERVER
+ssh_signature pki_do_sign_sessionid(const ssh_key key, const unsigned char
+        *hash, size_t hlen)
+{
+    ssh_signature sig;
+    int rc;
+
+    sig = ssh_signature_new();
+    if (sig == NULL) {
+        return NULL;
+    }
+    sig->type = key->type;
+    sig->type_c = key->type_c;
+
+    switch (key->type) {
+        case SSH_KEYTYPE_RSA:
+        case SSH_KEYTYPE_RSA1:
+            sig->rsa_sig = rsa_do_sign(hash, hlen, key->rsa);
+            if (sig->rsa_sig == NULL) {
+                ssh_signature_free(sig);
+                return NULL;
+            }
+            break;
+        case SSH_KEYTYPE_ECDSA:
+            sig->ecdsa_sig.r = bignum_new();
+            if (sig->ecdsa_sig.r == NULL) {
+                return NULL;
+            }
+
+            sig->ecdsa_sig.s = bignum_new();
+            if (sig->ecdsa_sig.s == NULL) {
+                bignum_free(sig->ecdsa_sig.r);
+                return NULL;
+            }
+
+            rc = mbedtls_ecdsa_sign(&key->ecdsa->grp, sig->ecdsa_sig.r,
+                    sig->ecdsa_sig.s, &key->ecdsa->d, hash, hlen,
+                    mbedtls_ctr_drbg_random, &ssh_mbedtls_ctr_drbg);
+            if (rc != 0) {
+                ssh_signature_free(sig);
+                return NULL;
+            }
+            break;
+        case SSH_KEYTYPE_ED25519:
+            /* ED25519 handled in caller */
+        default:
+            ssh_signature_free(sig);
+            return NULL;
+    }
+
+    return sig;
+}
+#endif /* WITH_SERVER */
+
+const char *pki_key_ecdsa_nid_to_name(int nid)
+{
+    switch (nid) {
+        case NID_mbedtls_nistp256:
+            return "ecdsa-sha2-nistp256";
+        case NID_mbedtls_nistp384:
+            return "ecdsa-sha2-nistp384";
+        case NID_mbedtls_nistp521:
+            return "ecdsa-sha2-nistp521";
+        default:
+            break;
+    }
+
+    return "unknown";
+}
+
+int pki_key_ecdsa_nid_from_name(const char *name)
+{
+    if (strcmp(name, "nistp256") == 0) {
+        return NID_mbedtls_nistp256;
+    } else if (strcmp(name, "nistp384") == 0) {
+        return NID_mbedtls_nistp384;
+    } else if (strcmp(name, "nistp521") == 0) {
+        return NID_mbedtls_nistp521;
+    }
+
+    return -1;
+}
+
+static mbedtls_ecp_group_id pki_key_ecdsa_nid_to_mbed_gid(int nid)
+{
+    switch (nid) {
+        case NID_mbedtls_nistp256:
+            return MBEDTLS_ECP_DP_SECP256R1;
+        case NID_mbedtls_nistp384:
+            return MBEDTLS_ECP_DP_SECP384R1;
+        case NID_mbedtls_nistp521:
+            return MBEDTLS_ECP_DP_SECP521R1;
+    }
+
+    return MBEDTLS_ECP_DP_NONE;
+}
+
+int pki_pubkey_build_ecdsa(ssh_key key, int nid, ssh_string e)
+{
+    int rc;
+    mbedtls_ecp_keypair keypair;
+    mbedtls_ecp_group group;
+    mbedtls_ecp_point Q;
+
+    key->ecdsa_nid = nid;
+    key->type_c = pki_key_ecdsa_nid_to_name(nid);
+
+    key->ecdsa = malloc(sizeof(mbedtls_ecdsa_context));
+    if (key->ecdsa == NULL) {
+        return SSH_ERROR;
+    }
+
+    mbedtls_ecdsa_init(key->ecdsa);
+    mbedtls_ecp_keypair_init(&keypair);
+    mbedtls_ecp_group_init(&group);
+    mbedtls_ecp_point_init(&Q);
+
+    rc = mbedtls_ecp_group_load(&group,
+            pki_key_ecdsa_nid_to_mbed_gid(nid));
+    if (rc != 0) {
+        goto fail;
+    }
+
+    rc = mbedtls_ecp_point_read_binary(&group, &Q, ssh_string_data(e),
+            ssh_string_len(e));
+    if (rc != 0) {
+        goto fail;
+    }
+
+    rc = mbedtls_ecp_copy(&keypair.Q, &Q);
+    if (rc != 0) {
+        goto fail;
+    }
+
+    rc = mbedtls_ecp_group_copy(&keypair.grp, &group);
+    if (rc != 0) {
+        goto fail;
+    }
+
+    mbedtls_mpi_init(&keypair.d);
+
+    rc = mbedtls_ecdsa_from_keypair(key->ecdsa, &keypair);
+    if (rc != 0) {
+        goto fail;
+    }
+
+    mbedtls_ecp_point_free(&Q);
+    mbedtls_ecp_group_free(&group);
+    mbedtls_ecp_keypair_free(&keypair);
+    return SSH_OK;
+fail:
+    mbedtls_ecdsa_free(key->ecdsa);
+    mbedtls_ecp_point_free(&Q);
+    mbedtls_ecp_group_free(&group);
+    mbedtls_ecp_keypair_free(&keypair);
+    SAFE_FREE(key->ecdsa);
+    return SSH_ERROR;
+}
+
+int pki_key_generate_ecdsa(ssh_key key, int parameter)
+{
+    int nid;
+    int ok;
+
+    switch (parameter) {
+        case 384:
+            nid = NID_mbedtls_nistp384;
+            break;
+        case 512:
+            nid = NID_mbedtls_nistp521;
+            break;
+        case 256:
+        default:
+            nid = NID_mbedtls_nistp256;
+            break;
+    }
+
+    key->ecdsa_nid = nid;
+    key->type = SSH_KEYTYPE_ECDSA;
+    key->type_c = pki_key_ecdsa_nid_to_name(nid);
+
+    key->ecdsa = malloc(sizeof(mbedtls_ecdsa_context));
+    if (key->ecdsa == NULL) {
+        return SSH_ERROR;
+    }
+
+    mbedtls_ecdsa_init(key->ecdsa);
+
+    ok = mbedtls_ecdsa_genkey(key->ecdsa, pki_key_ecdsa_nid_to_mbed_gid(nid),
+            mbedtls_ctr_drbg_random, &ssh_mbedtls_ctr_drbg);
+
+    if (ok != 0) {
+        mbedtls_ecdsa_free(key->ecdsa);
+        SAFE_FREE(key->ecdsa);
+    }
+
+    return SSH_OK;
+}
+#endif /* HAVE_LIBMBEDCRYPTO */
diff --git a/src/server.c b/src/server.c
index 3c1ee74c..321ed78c 100644
--- a/src/server.c
+++ b/src/server.c
@@ -107,6 +107,7 @@ static int server_set_kex(ssh_session session) {
                ",%s", session->srv.ecdsa_key->type_c);
   }
 #endif
+#ifdef HAVE_DSA
   if (session->srv.dsa_key != NULL) {
       len = strlen(hostkeys);
       keytype = ssh_key_type(session->srv.dsa_key);
@@ -114,6 +115,7 @@ static int server_set_kex(ssh_session session) {
       snprintf(hostkeys + len, sizeof(hostkeys) - len,
                ",%s", ssh_key_type_to_char(keytype));
   }
+#endif
   if (session->srv.rsa_key != NULL) {
       len = strlen(hostkeys);
       keytype = ssh_key_type(session->srv.rsa_key);
@@ -225,9 +227,11 @@ int ssh_get_key_params(ssh_session session, ssh_key *privkey){
     int rc;
 
     switch(session->srv.hostkey) {
+#ifdef HAVE_DSA
       case SSH_KEYTYPE_DSS:
         *privkey = session->srv.dsa_key;
         break;
+#endif
       case SSH_KEYTYPE_RSA:
       case SSH_KEYTYPE_RSA1:
         *privkey = session->srv.rsa_key;
diff --git a/src/session.c b/src/session.c
index 01773c52..f17d37c3 100644
--- a/src/session.c
+++ b/src/session.c
@@ -147,6 +147,7 @@ ssh_session ssh_new(void) {
       goto err;
     }
 
+#ifdef HAVE_DSA
     id = strdup("%d/id_dsa");
     if (id == NULL) {
       goto err;
@@ -155,6 +156,7 @@ ssh_session ssh_new(void) {
     if (rc == SSH_ERROR) {
       goto err;
     }
+#endif
 
     id = strdup("%d/identity");
     if (id == NULL) {
@@ -237,8 +239,10 @@ void ssh_free(ssh_session session) {
   ssh_agent_free(session->agent);
 #endif /* _WIN32 */
 
+#ifdef HAVE_DSA
   ssh_key_free(session->srv.dsa_key);
   session->srv.dsa_key = NULL;
+#endif
   ssh_key_free(session->srv.rsa_key);
   session->srv.rsa_key = NULL;
   ssh_key_free(session->srv.ecdsa_key);
diff --git a/src/threads.c b/src/threads.c
index 062c3b84..b85ac756 100644
--- a/src/threads.c
+++ b/src/threads.c
@@ -33,6 +33,10 @@
 #include "libssh/crypto.h"
 #include "libssh/threads.h"
 
+#ifdef HAVE_LIBMBEDCRYPTO
+#include <mbedtls/threading.h>
+#endif
+
 static int threads_noop (void **lock){
 	(void)lock;
   return 0;
@@ -100,6 +104,28 @@ static int libgcrypt_thread_init(void){
 	return SSH_OK;
 }
 #endif /* GCRYPT_VERSION_NUMBER */
+#elif defined HAVE_LIBMBEDCRYPTO
+static int libmbedcrypto_thread_init(void)
+{
+    if (user_callbacks == NULL) {
+        return SSH_ERROR;
+    }
+
+    if (user_callbacks == &ssh_threads_noop) {
+        return SSH_OK;
+    }
+#ifdef MBEDTLS_THREADING_ALT
+    else {
+        mbedtls_threading_set_alt(user_callbacks->mutex_init,
+                user_callbacks->mutex_destroy, user_callbacks->mutex_lock,
+                user_callbacks->mutex_unlock);
+    }
+#elif defined MBEDTLS_THREADING_PTHREAD
+    return SSH_OK;
+#else
+    return SSH_ERROR;
+#endif
+}
 #else /* HAVE_LIBGCRYPT */
 
 /* Libcrypto specific stuff */
@@ -181,6 +207,8 @@ int ssh_threads_init(void){
 	/* Then initialize the crypto libraries threading callbacks */
 #ifdef HAVE_LIBGCRYPT
 	ret = libgcrypt_thread_init();
+#elif HAVE_LIBMBEDCRYPTO
+    ret = libmbedcrypto_thread_init();
 #else /* Libcrypto */
 	ret = libcrypto_thread_init();
 #endif
@@ -191,6 +219,10 @@ int ssh_threads_init(void){
 
 void ssh_threads_finalize(void){
 #ifdef HAVE_LIBGCRYPT
+#elif HAVE_LIBMBEDCRYPTO
+#ifdef MBEDTLS_THREADING_ALT
+    mbedtls_threading_free_alt();
+#endif
 #else
 	libcrypto_thread_finalize();
 #endif
diff --git a/src/wrapper.c b/src/wrapper.c
index 877b807b..8ee04b49 100644
--- a/src/wrapper.c
+++ b/src/wrapper.c
@@ -113,21 +113,17 @@ void ssh_cipher_clear(struct ssh_cipher_struct *cipher){
     }
 
 #ifdef HAVE_LIBGCRYPT
-  if(cipher->key) {
+    if (cipher->key) {
         for (i = 0; i < (cipher->keylen / sizeof(gcry_cipher_hd_t)); i++) {
             gcry_cipher_close(cipher->key[i]);
         }
         SAFE_FREE(cipher->key);
     }
 #endif
-  if (cipher->ctx != NULL) {
+
     if (cipher->cleanup != NULL) {
         cipher->cleanup(cipher);
     }
-#ifdef HAVE_LIBCRYPTO
-    EVP_CIPHER_CTX_free(cipher->ctx);
-#endif
-  }
 }
 
 static void cipher_free(struct ssh_cipher_struct *cipher) {
diff --git a/tests/client/torture_knownhosts.c b/tests/client/torture_knownhosts.c
index 00aa8269..014347df 100644
--- a/tests/client/torture_knownhosts.c
+++ b/tests/client/torture_knownhosts.c
@@ -38,6 +38,7 @@
                "YgIytryNn7LLiwYfoSxvWigFrTTZsrVtCOYyNgklmffpGdzuC43wdANvTewfI9G" \
                "o71r8EXmEc228CrYPmb8Scv3mpXFK/BosohSGkPlEHu9lf3YjnknBicDaVtJOYp" \
                "wnXJPjZo2EhG79HxDRpjJHH"
+#ifdef HAVE_DSA
 #define BADDSA "AAAAB3NzaC1kc3MAAACBAITDKqGQ5aC5wHySG6ZdL1+BVBY2nLP5vzw3i3pvZfP" \
                "yNUS0UCwrt5pajsMvDRGXXebTJhWVonDnv8tpSgiuIBXMZrma8CU1KCFGRzwb/n8" \
                "cc5tJmIphlOUTrObjBmsRz7u1eZmoaddXC9ask6BNnt0DmhzYi2esL3mbardy8IN" \
@@ -48,6 +49,7 @@
                "EcxqLVllrNEvd2EGD9p16BYO2yaalYon8im59PtOcul2ay5XQ6rVDQ2T0pgNUpsI" \
                "h0dSi8VJXI1wes5HTyLsv9VBmU1uCXUUvufoQKfF/OcSH0ufcCpnd62g1/adZcy2" \
                "WJg=="
+#endif
 
 static int sshd_setup(void **state)
 {
@@ -185,6 +187,7 @@ static void torture_knownhosts_fail(void **state) {
     assert_int_equal(rc, SSH_SERVER_KNOWN_CHANGED);
 }
 
+#ifdef HAVE_DSA
 static void torture_knownhosts_other(void **state) {
     struct torture_state *s = *state;
     ssh_session session = s->ssh.session;
@@ -270,6 +273,7 @@ static void torture_knownhosts_other_auto(void **state) {
 
     /* session will be freed by session_teardown() */
 }
+#endif
 
 static void torture_knownhosts_conflict(void **state) {
     struct torture_state *s = *state;
@@ -296,7 +300,9 @@ static void torture_knownhosts_conflict(void **state) {
     file = fopen(known_hosts_file, "w");
     assert_true(file != NULL);
     fprintf(file, "127.0.0.10 ssh-rsa %s\n", BADRSA);
+#ifdef HAVE_DSA
     fprintf(file, "127.0.0.10 ssh-dss %s\n", BADDSA);
+#endif
     fclose(file);
 
     rc = ssh_connect(session);
@@ -354,15 +360,21 @@ static void torture_knownhosts_precheck(void **state) {
     file = fopen(known_hosts_file, "w");
     assert_true(file != NULL);
     fprintf(file, "127.0.0.10 ssh-rsa %s\n", BADRSA);
+#ifdef HAVE_DSA
     fprintf(file, "127.0.0.10 ssh-dss %s\n", BADDSA);
+#endif
     fclose(file);
 
     kex = ssh_knownhosts_algorithms(session);
     assert_true(kex != NULL);
     assert_string_equal(kex[0],"ssh-rsa");
+#ifdef HAVE_DSA
     assert_string_equal(kex[1],"ssh-dss");
     assert_true(kex[2]==NULL);
     free(kex[1]);
+#else
+    assert_true(kex[1]==NULL);
+#endif
     free(kex[0]);
     free(kex);
 }
@@ -376,12 +388,14 @@ int torture_run_tests(void) {
         cmocka_unit_test_setup_teardown(torture_knownhosts_fail,
                                         session_setup,
                                         session_teardown),
+#ifdef HAVE_DSA
         cmocka_unit_test_setup_teardown(torture_knownhosts_other,
                                         session_setup,
                                         session_teardown),
         cmocka_unit_test_setup_teardown(torture_knownhosts_other_auto,
                                         session_setup,
                                         session_teardown),
+#endif
         cmocka_unit_test_setup_teardown(torture_knownhosts_conflict,
                                         session_setup,
                                         session_teardown),
diff --git a/tests/pkd/pkd_daemon.c b/tests/pkd/pkd_daemon.c
index 61582b5a..a72f53f8 100644
--- a/tests/pkd/pkd_daemon.c
+++ b/tests/pkd/pkd_daemon.c
@@ -253,8 +253,10 @@ static int pkd_exec_hello(int fd, struct pkd_daemon_args *args) {
 
     if (type == PKD_RSA) {
         opts = SSH_BIND_OPTIONS_RSAKEY;
+#ifdef HAVE_DSA
     } else if (type == PKD_DSA) {
         opts = SSH_BIND_OPTIONS_DSAKEY;
+#endif
     } else if (type == PKD_ECDSA) {
         opts = SSH_BIND_OPTIONS_ECDSAKEY;
     } else {
diff --git a/tests/pkd/pkd_daemon.h b/tests/pkd/pkd_daemon.h
index c42573c1..cc5aa43f 100644
--- a/tests/pkd/pkd_daemon.h
+++ b/tests/pkd/pkd_daemon.h
@@ -10,7 +10,9 @@
 
 enum pkd_hostkey_type_e {
     PKD_RSA,
+#ifdef HAVE_DSA
     PKD_DSA,
+#endif
     PKD_ECDSA
 };
 
diff --git a/tests/pkd/pkd_hello.c b/tests/pkd/pkd_hello.c
index fe7c2276..aac33fcf 100644
--- a/tests/pkd/pkd_hello.c
+++ b/tests/pkd/pkd_hello.c
@@ -139,12 +139,14 @@ static int torture_pkd_setup_rsa(void **state) {
     return 0;
 }
 
+#ifdef HAVE_DSA
 static int torture_pkd_setup_dsa(void **state) {
     setup_dsa_key();
     *state = (void *) torture_pkd_setup(PKD_DSA, LIBSSH_DSA_TESTKEY);
 
     return 0;
 }
+#endif
 
 static int torture_pkd_setup_ecdsa_256(void **state) {
     setup_ecdsa_keys();
@@ -171,6 +173,7 @@ static int torture_pkd_setup_ecdsa_521(void **state) {
  * Test matrices: f(clientname, testname, ssh-command, setup-function, teardown-function).
  */
 
+#ifdef HAVE_DSA
 #define PKDTESTS_DEFAULT(f, client, cmd) \
     /* Default passes by server key type. */ \
     f(client, rsa_default,        cmd,  setup_rsa,        teardown) \
@@ -178,7 +181,16 @@ static int torture_pkd_setup_ecdsa_521(void **state) {
     f(client, ecdsa_256_default,  cmd,  setup_ecdsa_256,  teardown) \
     f(client, ecdsa_384_default,  cmd,  setup_ecdsa_384,  teardown) \
     f(client, ecdsa_521_default,  cmd,  setup_ecdsa_521,  teardown)
+#else
+#define PKDTESTS_DEFAULT(f, client, cmd) \
+    /* Default passes by server key type. */ \
+    f(client, rsa_default,        cmd,  setup_rsa,        teardown) \
+    f(client, ecdsa_256_default,  cmd,  setup_ecdsa_256,  teardown) \
+    f(client, ecdsa_384_default,  cmd,  setup_ecdsa_384,  teardown) \
+    f(client, ecdsa_521_default,  cmd,  setup_ecdsa_521,  teardown)
+#endif
 
+#ifdef HAVE_DSA
 #define PKDTESTS_KEX(f, client, kexcmd) \
     /* Kex algorithms. */ \
     f(client, rsa_curve25519_sha256,                  kexcmd("curve25519-sha256@xxxxxxxxxx"),  setup_rsa,        teardown) \
@@ -201,7 +213,28 @@ static int torture_pkd_setup_ecdsa_521(void **state) {
     f(client, ecdsa_521_ecdh_sha2_nistp256,           kexcmd("ecdh-sha2-nistp256 "),           setup_ecdsa_521,  teardown) \
     f(client, ecdsa_521_diffie_hellman_group14_sha1,  kexcmd("diffie-hellman-group14-sha1"),   setup_ecdsa_521,  teardown) \
     f(client, ecdsa_521_diffie_hellman_group1_sha1,   kexcmd("diffie-hellman-group1-sha1"),    setup_ecdsa_521,  teardown)
+#else
+#define PKDTESTS_KEX(f, client, kexcmd) \
+    /* Kex algorithms. */ \
+    f(client, rsa_curve25519_sha256,                  kexcmd("curve25519-sha256@xxxxxxxxxx"),  setup_rsa,        teardown) \
+    f(client, rsa_ecdh_sha2_nistp256,                 kexcmd("ecdh-sha2-nistp256 "),           setup_rsa,        teardown) \
+    f(client, rsa_diffie_hellman_group14_sha1,        kexcmd("diffie-hellman-group14-sha1"),   setup_rsa,        teardown) \
+    f(client, rsa_diffie_hellman_group1_sha1,         kexcmd("diffie-hellman-group1-sha1"),    setup_rsa,        teardown) \
+    f(client, ecdsa_256_curve25519_sha256,            kexcmd("curve25519-sha256@xxxxxxxxxx"),  setup_ecdsa_256,  teardown) \
+    f(client, ecdsa_256_ecdh_sha2_nistp256,           kexcmd("ecdh-sha2-nistp256 "),           setup_ecdsa_256,  teardown) \
+    f(client, ecdsa_256_diffie_hellman_group14_sha1,  kexcmd("diffie-hellman-group14-sha1"),   setup_ecdsa_256,  teardown) \
+    f(client, ecdsa_256_diffie_hellman_group1_sha1,   kexcmd("diffie-hellman-group1-sha1"),    setup_ecdsa_256,  teardown) \
+    f(client, ecdsa_384_curve25519_sha256,            kexcmd("curve25519-sha256@xxxxxxxxxx"),  setup_ecdsa_384,  teardown) \
+    f(client, ecdsa_384_ecdh_sha2_nistp256,           kexcmd("ecdh-sha2-nistp256 "),           setup_ecdsa_384,  teardown) \
+    f(client, ecdsa_384_diffie_hellman_group14_sha1,  kexcmd("diffie-hellman-group14-sha1"),   setup_ecdsa_384,  teardown) \
+    f(client, ecdsa_384_diffie_hellman_group1_sha1,   kexcmd("diffie-hellman-group1-sha1"),    setup_ecdsa_384,  teardown) \
+    f(client, ecdsa_521_curve25519_sha256,            kexcmd("curve25519-sha256@xxxxxxxxxx"),  setup_ecdsa_521,  teardown) \
+    f(client, ecdsa_521_ecdh_sha2_nistp256,           kexcmd("ecdh-sha2-nistp256 "),           setup_ecdsa_521,  teardown) \
+    f(client, ecdsa_521_diffie_hellman_group14_sha1,  kexcmd("diffie-hellman-group14-sha1"),   setup_ecdsa_521,  teardown) \
+    f(client, ecdsa_521_diffie_hellman_group1_sha1,   kexcmd("diffie-hellman-group1-sha1"),    setup_ecdsa_521,  teardown)
+#endif
 
+#ifdef HAVE_DSA
 #define PKDTESTS_CIPHER(f, client, ciphercmd) \
     /* Ciphers. */ \
     f(client, rsa_3des_cbc,            ciphercmd("3des-cbc"),      setup_rsa,        teardown) \
@@ -234,7 +267,36 @@ static int torture_pkd_setup_ecdsa_521(void **state) {
     f(client, ecdsa_521_aes256_cbc,    ciphercmd("aes256-cbc"),    setup_ecdsa_521,  teardown) \
     f(client, ecdsa_521_aes256_ctr,    ciphercmd("aes256-ctr"),    setup_ecdsa_521,  teardown) \
     f(client, ecdsa_521_blowfish_cbc,  ciphercmd("blowfish-cbc"),  setup_ecdsa_521,  teardown)
+#else
+#define PKDTESTS_CIPHER(f, client, ciphercmd) \
+    /* Ciphers. */ \
+    f(client, rsa_3des_cbc,            ciphercmd("3des-cbc"),      setup_rsa,        teardown) \
+    f(client, rsa_aes128_cbc,          ciphercmd("aes128-cbc"),    setup_rsa,        teardown) \
+    f(client, rsa_aes128_ctr,          ciphercmd("aes128-ctr"),    setup_rsa,        teardown) \
+    f(client, rsa_aes256_cbc,          ciphercmd("aes256-cbc"),    setup_rsa,        teardown) \
+    f(client, rsa_aes256_ctr,          ciphercmd("aes256-ctr"),    setup_rsa,        teardown) \
+    f(client, rsa_blowfish_cbc,        ciphercmd("blowfish-cbc"),  setup_rsa,        teardown) \
+    f(client, ecdsa_256_3des_cbc,      ciphercmd("3des-cbc"),      setup_ecdsa_256,  teardown) \
+    f(client, ecdsa_256_aes128_cbc,    ciphercmd("aes128-cbc"),    setup_ecdsa_256,  teardown) \
+    f(client, ecdsa_256_aes128_ctr,    ciphercmd("aes128-ctr"),    setup_ecdsa_256,  teardown) \
+    f(client, ecdsa_256_aes256_cbc,    ciphercmd("aes256-cbc"),    setup_ecdsa_256,  teardown) \
+    f(client, ecdsa_256_aes256_ctr,    ciphercmd("aes256-ctr"),    setup_ecdsa_256,  teardown) \
+    f(client, ecdsa_256_blowfish_cbc,  ciphercmd("blowfish-cbc"),  setup_ecdsa_256,  teardown) \
+    f(client, ecdsa_384_3des_cbc,      ciphercmd("3des-cbc"),      setup_ecdsa_384,  teardown) \
+    f(client, ecdsa_384_aes128_cbc,    ciphercmd("aes128-cbc"),    setup_ecdsa_384,  teardown) \
+    f(client, ecdsa_384_aes128_ctr,    ciphercmd("aes128-ctr"),    setup_ecdsa_384,  teardown) \
+    f(client, ecdsa_384_aes256_cbc,    ciphercmd("aes256-cbc"),    setup_ecdsa_384,  teardown) \
+    f(client, ecdsa_384_aes256_ctr,    ciphercmd("aes256-ctr"),    setup_ecdsa_384,  teardown) \
+    f(client, ecdsa_384_blowfish_cbc,  ciphercmd("blowfish-cbc"),  setup_ecdsa_384,  teardown) \
+    f(client, ecdsa_521_3des_cbc,      ciphercmd("3des-cbc"),      setup_ecdsa_521,  teardown) \
+    f(client, ecdsa_521_aes128_cbc,    ciphercmd("aes128-cbc"),    setup_ecdsa_521,  teardown) \
+    f(client, ecdsa_521_aes128_ctr,    ciphercmd("aes128-ctr"),    setup_ecdsa_521,  teardown) \
+    f(client, ecdsa_521_aes256_cbc,    ciphercmd("aes256-cbc"),    setup_ecdsa_521,  teardown) \
+    f(client, ecdsa_521_aes256_ctr,    ciphercmd("aes256-ctr"),    setup_ecdsa_521,  teardown) \
+    f(client, ecdsa_521_blowfish_cbc,  ciphercmd("blowfish-cbc"),  setup_ecdsa_521,  teardown)
+#endif
 
+#ifdef HAVE_DSA
 #define PKDTESTS_CIPHER_AES192(f, client, ciphercmd) \
     /* Ciphers. */ \
     f(client, rsa_aes192_cbc,          ciphercmd("aes192-cbc"),    setup_rsa,        teardown) \
@@ -247,7 +309,20 @@ static int torture_pkd_setup_ecdsa_521(void **state) {
     f(client, ecdsa_384_aes192_ctr,    ciphercmd("aes192-ctr"),    setup_ecdsa_384,  teardown) \
     f(client, ecdsa_521_aes192_cbc,    ciphercmd("aes192-cbc"),    setup_ecdsa_521,  teardown) \
     f(client, ecdsa_521_aes192_ctr,    ciphercmd("aes192-ctr"),    setup_ecdsa_521,  teardown)
+#else
+#define PKDTESTS_CIPHER_AES192(f, client, ciphercmd) \
+    /* Ciphers. */ \
+    f(client, rsa_aes192_cbc,          ciphercmd("aes192-cbc"),    setup_rsa,        teardown) \
+    f(client, rsa_aes192_ctr,          ciphercmd("aes192-ctr"),    setup_rsa,        teardown) \
+    f(client, ecdsa_256_aes192_cbc,    ciphercmd("aes192-cbc"),    setup_ecdsa_256,  teardown) \
+    f(client, ecdsa_256_aes192_ctr,    ciphercmd("aes192-ctr"),    setup_ecdsa_256,  teardown) \
+    f(client, ecdsa_384_aes192_cbc,    ciphercmd("aes192-cbc"),    setup_ecdsa_384,  teardown) \
+    f(client, ecdsa_384_aes192_ctr,    ciphercmd("aes192-ctr"),    setup_ecdsa_384,  teardown) \
+    f(client, ecdsa_521_aes192_cbc,    ciphercmd("aes192-cbc"),    setup_ecdsa_521,  teardown) \
+    f(client, ecdsa_521_aes192_ctr,    ciphercmd("aes192-ctr"),    setup_ecdsa_521,  teardown)
+#endif
 
+#ifdef HAVE_DSA
 #define PKDTESTS_MAC(f, client, maccmd) \
     /* MACs. */ \
     f(client, rsa_hmac_sha1,            maccmd("hmac-sha1"),      setup_rsa,        teardown) \
@@ -265,6 +340,22 @@ static int torture_pkd_setup_ecdsa_521(void **state) {
     f(client, ecdsa_256_hmac_sha2_512,  maccmd("hmac-sha2-512"),  setup_ecdsa_256,  teardown) \
     f(client, ecdsa_384_hmac_sha2_512,  maccmd("hmac-sha2-512"),  setup_ecdsa_384,  teardown) \
     f(client, ecdsa_521_hmac_sha2_512,  maccmd("hmac-sha2-512"),  setup_ecdsa_521,  teardown)
+#else
+#define PKDTESTS_MAC(f, client, maccmd) \
+    /* MACs. */ \
+    f(client, rsa_hmac_sha1,            maccmd("hmac-sha1"),      setup_rsa,        teardown) \
+    f(client, ecdsa_256_hmac_sha1,      maccmd("hmac-sha1"),      setup_ecdsa_256,  teardown) \
+    f(client, ecdsa_384_hmac_sha1,      maccmd("hmac-sha1"),      setup_ecdsa_384,  teardown) \
+    f(client, ecdsa_521_hmac_sha1,      maccmd("hmac-sha1"),      setup_ecdsa_521,  teardown) \
+    f(client, rsa_hmac_sha2_256,        maccmd("hmac-sha2-256"),  setup_rsa,        teardown) \
+    f(client, ecdsa_256_hmac_sha2_256,  maccmd("hmac-sha2-256"),  setup_ecdsa_256,  teardown) \
+    f(client, ecdsa_384_hmac_sha2_256,  maccmd("hmac-sha2-256"),  setup_ecdsa_384,  teardown) \
+    f(client, ecdsa_521_hmac_sha2_256,  maccmd("hmac-sha2-256"),  setup_ecdsa_521,  teardown) \
+    f(client, rsa_hmac_sha2_512,        maccmd("hmac-sha2-512"),  setup_rsa,        teardown) \
+    f(client, ecdsa_256_hmac_sha2_512,  maccmd("hmac-sha2-512"),  setup_ecdsa_256,  teardown) \
+    f(client, ecdsa_384_hmac_sha2_512,  maccmd("hmac-sha2-512"),  setup_ecdsa_384,  teardown) \
+    f(client, ecdsa_521_hmac_sha2_512,  maccmd("hmac-sha2-512"),  setup_ecdsa_521,  teardown)
+#endif
 
 static void torture_pkd_client_noop(void **state) {
     struct pkd_state *pstate = (struct pkd_state *) (*state);
@@ -311,6 +402,7 @@ static void torture_pkd_runtest(const char *testname,
  * Actual test functions are emitted here.
  */
 
+#ifdef HAVE_DSA
 #define CLIENT_ID_FILE OPENSSH_DSA_TESTKEY
 PKDTESTS_DEFAULT(emit_keytest, openssh_dsa, OPENSSH_CMD)
 PKDTESTS_KEX(emit_keytest, openssh_dsa, OPENSSH_KEX_CMD)
@@ -318,6 +410,7 @@ PKDTESTS_CIPHER(emit_keytest, openssh_dsa, OPENSSH_CIPHER_CMD)
 PKDTESTS_CIPHER_AES192(emit_keytest, openssh_dsa, OPENSSH_CIPHER_CMD)
 PKDTESTS_MAC(emit_keytest, openssh_dsa, OPENSSH_MAC_CMD)
 #undef CLIENT_ID_FILE
+#endif
 
 #define CLIENT_ID_FILE OPENSSH_RSA_TESTKEY
 PKDTESTS_DEFAULT(emit_keytest, openssh_rsa, OPENSSH_CMD)
@@ -376,11 +469,13 @@ struct {
     const struct CMUnitTest test[3]; /* requires setup + test + teardown */
 } testmap[] = {
     /* OpenSSH */
+#ifdef HAVE_DSA
     PKDTESTS_DEFAULT(emit_testmap, openssh_dsa, OPENSSH_CMD)
     PKDTESTS_KEX(emit_testmap, openssh_dsa, OPENSSH_KEX_CMD)
     PKDTESTS_CIPHER(emit_testmap, openssh_dsa, OPENSSH_CIPHER_CMD)
     PKDTESTS_CIPHER_AES192(emit_testmap, openssh_dsa, OPENSSH_CIPHER_CMD)
     PKDTESTS_MAC(emit_testmap, openssh_dsa, OPENSSH_MAC_CMD)
+#endif
 
     PKDTESTS_DEFAULT(emit_testmap, openssh_rsa, OPENSSH_CMD)
     PKDTESTS_KEX(emit_testmap, openssh_rsa, OPENSSH_KEX_CMD)
@@ -418,11 +513,13 @@ static int pkd_run_tests(void) {
     int tindex = 0;
 
     const struct CMUnitTest openssh_tests[] = {
+#ifdef HAVE_DSA
         PKDTESTS_DEFAULT(emit_unit_test_comma, openssh_dsa, OPENSSH_CMD)
         PKDTESTS_KEX(emit_unit_test_comma, openssh_dsa, OPENSSH_KEX_CMD)
         PKDTESTS_CIPHER(emit_unit_test_comma, openssh_dsa, OPENSSH_CIPHER_CMD)
         PKDTESTS_CIPHER_AES192(emit_unit_test_comma, openssh_dsa, OPENSSH_CIPHER_CMD)
         PKDTESTS_MAC(emit_unit_test_comma, openssh_dsa, OPENSSH_MAC_CMD)
+#endif
 
         PKDTESTS_DEFAULT(emit_unit_test_comma, openssh_rsa, OPENSSH_CMD)
         PKDTESTS_KEX(emit_unit_test_comma, openssh_rsa, OPENSSH_KEX_CMD)
@@ -508,7 +605,9 @@ static int pkd_run_tests(void) {
 
     /* Clean up any server keys that were generated. */
     cleanup_rsa_key();
+#ifdef HAVE_DSA
     cleanup_dsa_key();
+#endif
     cleanup_ecdsa_keys();
 
     return rc;
diff --git a/tests/pkd/pkd_keyutil.c b/tests/pkd/pkd_keyutil.c
index e1e1ecb8..7cb2ed48 100644
--- a/tests/pkd/pkd_keyutil.c
+++ b/tests/pkd/pkd_keyutil.c
@@ -27,6 +27,7 @@ void setup_rsa_key() {
     assert_int_equal(rc, 0);
 }
 
+#ifdef HAVE_DSA
 void setup_dsa_key() {
     int rc = 0;
     if (access(LIBSSH_DSA_TESTKEY, F_OK) != 0) {
@@ -35,6 +36,7 @@ void setup_dsa_key() {
     }
     assert_int_equal(rc, 0);
 }
+#endif
 
 void setup_ecdsa_keys() {
     int rc = 0;
@@ -65,9 +67,11 @@ void cleanup_rsa_key() {
     cleanup_key(LIBSSH_RSA_TESTKEY, LIBSSH_RSA_TESTKEY ".pub");
 }
 
+#ifdef HAVE_DSA
 void cleanup_dsa_key() {
     cleanup_key(LIBSSH_DSA_TESTKEY, LIBSSH_DSA_TESTKEY ".pub");
 }
+#endif
 
 void cleanup_ecdsa_keys() {
     cleanup_key(LIBSSH_ECDSA_256_TESTKEY, LIBSSH_ECDSA_256_TESTKEY ".pub");
@@ -78,11 +82,13 @@ void cleanup_ecdsa_keys() {
 void setup_openssh_client_keys() {
     int rc = 0;
 
+#ifdef HAVE_DSA
     if (access(OPENSSH_DSA_TESTKEY, F_OK) != 0) {
         rc = system_checked(OPENSSH_KEYGEN " -t dsa -q -N \"\" -f "
                             OPENSSH_DSA_TESTKEY);
     }
     assert_int_equal(rc, 0);
+#endif
 
     if (access(OPENSSH_RSA_TESTKEY, F_OK) != 0) {
         rc = system_checked(OPENSSH_KEYGEN " -t rsa -q -N \"\" -f "
@@ -116,7 +122,9 @@ void setup_openssh_client_keys() {
 }
 
 void cleanup_openssh_client_keys() {
+#ifdef HAVE_DSA
     cleanup_key(OPENSSH_DSA_TESTKEY, OPENSSH_DSA_TESTKEY ".pub");
+#endif
     cleanup_key(OPENSSH_RSA_TESTKEY, OPENSSH_RSA_TESTKEY ".pub");
     cleanup_key(OPENSSH_ECDSA256_TESTKEY, OPENSSH_ECDSA256_TESTKEY ".pub");
     cleanup_key(OPENSSH_ECDSA384_TESTKEY, OPENSSH_ECDSA384_TESTKEY ".pub");
diff --git a/tests/pkd/pkd_keyutil.h b/tests/pkd/pkd_keyutil.h
index 8e9de009..3d0ae5a7 100644
--- a/tests/pkd/pkd_keyutil.h
+++ b/tests/pkd/pkd_keyutil.h
@@ -7,22 +7,32 @@
 #ifndef __PKD_KEYUTIL_H__
 #define __PKD_KEYUTIL_H__
 
+#include "config.h"
+
 /* Server keys. */
+#ifdef HAVE_DSA
 #define LIBSSH_DSA_TESTKEY        "libssh_testkey.id_dsa"
+#endif
 #define LIBSSH_RSA_TESTKEY        "libssh_testkey.id_rsa"
 #define LIBSSH_ECDSA_256_TESTKEY  "libssh_testkey.id_ecdsa256"
 #define LIBSSH_ECDSA_384_TESTKEY  "libssh_testkey.id_ecdsa384"
 #define LIBSSH_ECDSA_521_TESTKEY  "libssh_testkey.id_ecdsa521"
 
+#ifdef HAVE_DSA
 void setup_dsa_key(void);
+#endif
 void setup_rsa_key(void);
 void setup_ecdsa_keys(void);
+#ifdef HAVE_DSA
 void cleanup_dsa_key(void);
+#endif
 void cleanup_rsa_key(void);
 void cleanup_ecdsa_keys(void);
 
 /* Client keys. */
+#ifdef HAVE_DSA
 #define OPENSSH_DSA_TESTKEY       "openssh_testkey.id_dsa"
+#endif
 #define OPENSSH_RSA_TESTKEY       "openssh_testkey.id_rsa"
 #define OPENSSH_ECDSA256_TESTKEY  "openssh_testkey.id_ecdsa256"
 #define OPENSSH_ECDSA384_TESTKEY  "openssh_testkey.id_ecdsa384"
diff --git a/tests/test_ssh_bind_accept_fd.c b/tests/test_ssh_bind_accept_fd.c
index 7611cf4c..5aa8211a 100644
--- a/tests/test_ssh_bind_accept_fd.c
+++ b/tests/test_ssh_bind_accept_fd.c
@@ -73,10 +73,18 @@ void ssh_server() {
     errx(1, "ssh_bind_new");
   }
 
+#ifdef HAVE_DSA
+  /*TODO mbedtls this is probably required */
   if (ssh_bind_options_set(bind, SSH_BIND_OPTIONS_DSAKEY,
                            options.server_keyfile) != SSH_OK) {
     errx(1, "ssh_bind_options_set(SSH_BIND_OPTIONS_DSAKEY");
   }
+#else
+  if (ssh_bind_options_set(bind, SSH_BIND_OPTIONS_RSAKEY,
+                           options.server_keyfile) != SSH_OK) {
+    errx(1, "ssh_bind_options_set(SSH_BIND_OPTIONS_RSAKEY");
+  }
+#endif
 
   session = ssh_new();
   if (!session) {
diff --git a/tests/torture.c b/tests/torture.c
index 545fc2e3..7a23ec51 100644
--- a/tests/torture.c
+++ b/tests/torture.c
@@ -113,6 +113,7 @@ static const char torture_rsa_testkey_cert[] =
         "neB6OdgTpKFsmgPZVtqrvhjw+b5T8a4W4iWSl+6wg6gowAm "
         "rsa_privkey.pub\n";
 
+#ifdef HAVE_DSA
 static const char torture_dsa_testkey[] =
         "-----BEGIN DSA PRIVATE KEY-----\n"
         "MIIBuwIBAAKBgQCUyvVPEkn3UnZDjzCzSzSHpTltzr0Ec+1mz/JACjHMBJ9C/W/P\n"
@@ -167,6 +168,7 @@ static const char torture_dsa_testkey_cert[] =
         "4mMXgzaLViFtcwah6wHGlW0UPQMvrq/RqigAkyUszSccfibkIXJ+wGAgsRYhVAMwME"
         "JqPZ6GHOEIjLBKUegsclHb7Pk0YO8Auaw== "
         "aris@aris-air\n";
+#endif
 
 static const char torture_rsa_testkey_pp[] =
         "-----BEGIN RSA PRIVATE KEY-----\n"
@@ -200,6 +202,7 @@ static const char torture_rsa_testkey_pp[] =
         "JSvUyxoaZUjQkT7iF94HsF+FVVJdI55UjgnMiZ0d5vKffWyTHYcYHkFYaSloAMWN\n"
         "-----END RSA PRIVATE KEY-----\n";
 
+#ifdef HAVE_DSA
 static const char torture_dsa_testkey_pp[] =
         "-----BEGIN DSA PRIVATE KEY-----\n"
         "Proc-Type: 4,ENCRYPTED\n"
@@ -216,6 +219,7 @@ static const char torture_dsa_testkey_pp[] =
         "HTSuHZ7edjoWqwnl/vkc3+nG//IEj8LqAacx0i4krDcQpGuQ6BnPfwPFco2NQQpw\n"
         "wHBOL6HrOnD+gGs6DUFwzA==\n"
         "-----END DSA PRIVATE KEY-----\n";
+#endif
 
 static const char torture_ecdsa256_testkey[] =
         "-----BEGIN EC PRIVATE KEY-----\n"
@@ -571,9 +575,11 @@ ssh_bind torture_ssh_bind(const char *addr,
     }
 
     switch (key_type) {
+#ifdef HAVE_DSA
         case SSH_KEYTYPE_DSS:
             opts = SSH_BIND_OPTIONS_DSAKEY;
             break;
+#endif
         case SSH_KEYTYPE_RSA:
             opts = SSH_BIND_OPTIONS_RSAKEY;
             break;
@@ -694,6 +700,7 @@ static const char *torture_get_testkey_internal(enum ssh_keytypes_e type,
                                                 int pubkey)
 {
     switch (type) {
+#ifdef HAVE_DSA
     case SSH_KEYTYPE_DSS:
         if (pubkey) {
             return torture_dsa_testkey_pub;
@@ -701,6 +708,7 @@ static const char *torture_get_testkey_internal(enum ssh_keytypes_e type,
             return torture_dsa_testkey_pp;
         }
         return torture_dsa_testkey;
+#endif
     case SSH_KEYTYPE_RSA:
        if (pubkey) {
                 return torture_rsa_testkey_pub;
@@ -738,8 +746,10 @@ static const char *torture_get_testkey_internal(enum ssh_keytypes_e type,
             return torture_ed25519_testkey_pp;
         }
         return torture_ed25519_testkey;
+#ifdef HAVE_DSA
     case SSH_KEYTYPE_DSS_CERT01:
         return torture_dsa_testkey_cert;
+#endif
     case SSH_KEYTYPE_RSA_CERT01:
         return torture_rsa_testkey_cert;
     case SSH_KEYTYPE_RSA1:
@@ -859,7 +869,9 @@ void torture_setup_socket_dir(void **state)
 static void torture_setup_create_sshd_config(void **state)
 {
     struct torture_state *s = *state;
+#ifdef HAVE_DSA
     char dsa_hostkey[1024];
+#endif
     char rsa_hostkey[1024];
     char ecdsa_hostkey[1024];
     char trusted_ca_pubkey[1024];
@@ -879,7 +891,9 @@ static void torture_setup_create_sshd_config(void **state)
     const char config_string[]=
              "Port 22\n"
              "ListenAddress 127.0.0.10\n"
+#ifdef HAVE_DSA
              "HostKey %s\n"
+#endif
              "HostKey %s\n"
              "HostKey %s\n"
              "\n"
@@ -898,7 +912,11 @@ static void torture_setup_create_sshd_config(void **state)
              "UsePAM yes\n"
              "\n"
 #if (OPENSSH_VERSION_MAJOR == 6 && OPENSSH_VERSION_MINOR >= 7) || (OPENSSH_VERSION_MAJOR >= 7)
+#ifdef HAVE_DSA
              "HostKeyAlgorithms +ssh-dss\n"
+#else
+             "HostKeyAlgorithms +ssh-rsa\n"
+#endif
              "Ciphers +3des-cbc,aes128-cbc,aes192-cbc,aes256-cbc,blowfish-cbc\n"
              "KexAlgorithms +diffie-hellman-group1-sha1"
 #else
@@ -932,11 +950,13 @@ static void torture_setup_create_sshd_config(void **state)
     rc = mkdir(sshd_path, 0755);
     assert_return_code(rc, errno);
 
+#ifdef HAVE_DSA
     snprintf(dsa_hostkey,
              sizeof(dsa_hostkey),
              "%s/sshd/ssh_host_dsa_key",
              s->socket_dir);
     torture_write_file(dsa_hostkey, torture_get_testkey(SSH_KEYTYPE_DSS, 0, 0));
+#endif
 
     snprintf(rsa_hostkey,
              sizeof(rsa_hostkey),
@@ -973,7 +993,9 @@ static void torture_setup_create_sshd_config(void **state)
 
     snprintf(sshd_config, sizeof(sshd_config),
              config_string,
+#ifdef HAVE_DSA
              dsa_hostkey,
+#endif
              rsa_hostkey,
              ecdsa_hostkey,
              trusted_ca_pubkey,
diff --git a/tests/unittests/torture_keyfiles.c b/tests/unittests/torture_keyfiles.c
index e5f054f9..6573711b 100644
--- a/tests/unittests/torture_keyfiles.c
+++ b/tests/unittests/torture_keyfiles.c
@@ -4,7 +4,9 @@
 #include "legacy.c"
 
 #define LIBSSH_RSA_TESTKEY "libssh_testkey.id_rsa"
+#ifdef HAVE_DSA
 #define LIBSSH_DSA_TESTKEY "libssh_testkey.id_dsa"
+#endif
 
 static int setup_rsa_key(void **state)
 {
@@ -24,6 +26,7 @@ static int setup_rsa_key(void **state)
     return 0;
 }
 
+#ifdef HAVE_DSA
 static int setup_dsa_key(void **state)
 {
     ssh_session session;
@@ -41,6 +44,7 @@ static int setup_dsa_key(void **state)
 
     return 0;
 }
+#endif
 
 static int setup_both_keys(void **state) {
     int rc;
@@ -49,9 +53,11 @@ static int setup_both_keys(void **state) {
     if (rc != 0) {
         return rc;
     }
+#ifdef HAVE_DSA
     ssh_free(*state);
 
     rc = setup_dsa_key(state);
+#endif
 
     return rc;
 }
@@ -65,10 +71,12 @@ static int setup_both_keys_passphrase(void **state)
     torture_write_file(LIBSSH_RSA_TESTKEY ".pub",
                        torture_get_testkey_pub(SSH_KEYTYPE_RSA, 0));
 
+#ifdef HAVE_DSA
     torture_write_file(LIBSSH_DSA_TESTKEY,
                        torture_get_testkey(SSH_KEYTYPE_DSS, 0, 1));
     torture_write_file(LIBSSH_DSA_TESTKEY ".pub",
                        torture_get_testkey_pub(SSH_KEYTYPE_DSS, 0));
+#endif
 
     session = ssh_new();
     *state = session;
@@ -78,8 +86,10 @@ static int setup_both_keys_passphrase(void **state)
 
 static int teardown(void **state)
 {
+#ifdef HAVE_DSA
     unlink(LIBSSH_DSA_TESTKEY);
     unlink(LIBSSH_DSA_TESTKEY ".pub");
+#endif
 
     unlink(LIBSSH_RSA_TESTKEY);
     unlink(LIBSSH_RSA_TESTKEY ".pub");
@@ -214,12 +224,14 @@ static void torture_privatekey_from_file(void **state) {
         key = NULL;
     }
 
+#ifdef HAVE_DSA
     key = privatekey_from_file(session, LIBSSH_DSA_TESTKEY, SSH_KEYTYPE_DSS, NULL);
     assert_true(key != NULL);
     if (key != NULL) {
         privatekey_free(key);
         key = NULL;
     }
+#endif
 
     /* Test the automatic type discovery */
     key = privatekey_from_file(session, LIBSSH_RSA_TESTKEY, 0, NULL);
@@ -229,12 +241,14 @@ static void torture_privatekey_from_file(void **state) {
         key = NULL;
     }
 
+#ifdef HAVE_DSA
     key = privatekey_from_file(session, LIBSSH_DSA_TESTKEY, 0, NULL);
     assert_true(key != NULL);
     if (key != NULL) {
         privatekey_free(key);
         key = NULL;
     }
+#endif
 }
 
 /**
@@ -251,12 +265,14 @@ static void torture_privatekey_from_file_passphrase(void **state) {
         key = NULL;
     }
 
+#ifdef HAVE_DSA
     key = privatekey_from_file(session, LIBSSH_DSA_TESTKEY, SSH_KEYTYPE_DSS, TORTURE_TESTKEY_PASSWORD);
     assert_true(key != NULL);
     if (key != NULL) {
         privatekey_free(key);
         key = NULL;
     }
+#endif
 
     /* Test the automatic type discovery */
     key = privatekey_from_file(session, LIBSSH_RSA_TESTKEY, 0, TORTURE_TESTKEY_PASSWORD);
@@ -266,12 +282,14 @@ static void torture_privatekey_from_file_passphrase(void **state) {
         key = NULL;
     }
 
+#ifdef HAVE_DSA
     key = privatekey_from_file(session, LIBSSH_DSA_TESTKEY, 0, TORTURE_TESTKEY_PASSWORD);
     assert_true(key != NULL);
     if (key != NULL) {
         privatekey_free(key);
         key = NULL;
     }
+#endif
 }
 
 int torture_run_tests(void) {
diff --git a/tests/unittests/torture_misc.c b/tests/unittests/torture_misc.c
index bc16dfb0..1d0e0f5c 100644
--- a/tests/unittests/torture_misc.c
+++ b/tests/unittests/torture_misc.c
@@ -205,6 +205,147 @@ static void torture_timeout_update(void **state){
     assert_int_equal(ssh_timeout_update(&ts,-1),-1);
 }
 
+static void torture_ssh_analyze_banner(void **state) {
+    int rc = 0;
+    int ssh1 = 0;
+    int ssh2 = 0;
+    ssh_session session = NULL;
+    (void) state;
+
+#define reset_banner_test() \
+    do {                           \
+        rc = 0;                    \
+        ssh1 = 0;                  \
+        ssh2 = 0;                  \
+        ssh_free(session);         \
+        session = ssh_new();       \
+        assert_non_null(session);  \
+    } while (0)
+
+#define assert_banner_rejected(is_server) \
+    do {                                                            \
+        rc = ssh_analyze_banner(session, is_server, &ssh1, &ssh2);  \
+        assert_int_not_equal(0, rc);                                \
+    } while (0);
+
+#define assert_client_banner_rejected(banner) \
+    do {                                         \
+        reset_banner_test();                     \
+        session->clientbanner = strdup(banner);  \
+        assert_non_null(session->clientbanner);  \
+        assert_banner_rejected(1 /*server*/);    \
+        SAFE_FREE(session->clientbanner);        \
+    } while (0)
+
+#define assert_server_banner_rejected(banner) \
+    do {                                         \
+        reset_banner_test();                     \
+        session->serverbanner = strdup(banner);  \
+        assert_non_null(session->serverbanner);  \
+        assert_banner_rejected(0 /*client*/);    \
+        SAFE_FREE(session->serverbanner);        \
+    } while (0)
+
+#define assert_banner_accepted(is_server, expected_ssh1, expected_ssh2) \
+    do {                                                            \
+        rc = ssh_analyze_banner(session, is_server, &ssh1, &ssh2);  \
+        assert_int_equal(0, rc);                                    \
+        assert_int_equal(expected_ssh1, ssh1);                      \
+        assert_int_equal(expected_ssh2, ssh2);                      \
+    } while (0)
+
+#define assert_client_banner_accepted(banner, e1, e2) \
+    do {                                               \
+        reset_banner_test();                           \
+        session->clientbanner = strdup(banner);        \
+        assert_non_null(session->clientbanner);        \
+        assert_banner_accepted(1 /*server*/, e1, e2);  \
+        SAFE_FREE(session->clientbanner);              \
+    } while (0)
+
+#define assert_server_banner_accepted(banner, e1, e2) \
+    do {                                               \
+        reset_banner_test();                           \
+        session->serverbanner = strdup(banner);        \
+        assert_non_null(session->serverbanner);        \
+        assert_banner_accepted(0 /*client*/, e1, e2);  \
+        SAFE_FREE(session->serverbanner);              \
+    } while (0)
+
+    /* no banner is set */
+    reset_banner_test();
+    assert_banner_rejected(0 /*client*/);
+    reset_banner_test();
+    assert_banner_rejected(1 /*server*/);
+
+    /* banner is too short */
+    assert_client_banner_rejected("abc");
+    assert_server_banner_rejected("abc");
+
+    /* banner doesn't start "SSH-" */
+    assert_client_banner_rejected("abc-2.0");
+    assert_server_banner_rejected("abc-2.0");
+
+    /* SSH v1 */
+    assert_client_banner_accepted("SSH-1.0", 1, 0);
+    assert_server_banner_accepted("SSH-1.0", 1, 0);
+
+    /* SSH v1.9 gets counted as both v1 and v2 */
+    assert_client_banner_accepted("SSH-1.9", 1, 1);
+    assert_server_banner_accepted("SSH-1.9", 1, 1);
+
+    /* SSH v2 */
+    assert_client_banner_accepted("SSH-2.0", 0, 1);
+    assert_server_banner_accepted("SSH-2.0", 0, 1);
+
+    /* OpenSSH banners: too short to extract major and minor versions */
+    assert_client_banner_accepted("SSH-2.0-OpenSSH", 0, 1);
+    assert_int_equal(0, session->openssh);
+    assert_server_banner_accepted("SSH-2.0-OpenSSH", 0, 1);
+    assert_int_equal(0, session->openssh);
+
+    /* OpenSSH banners: big enough to extract major and minor versions */
+    assert_client_banner_accepted("SSH-2.0-OpenSSH_5.9p1", 0, 1);
+    assert_int_equal(SSH_VERSION_INT(5, 9, 0), session->openssh);
+    assert_server_banner_accepted("SSH-2.0-OpenSSH_5.9p1", 0, 1);
+    assert_int_equal(SSH_VERSION_INT(5, 9, 0), session->openssh);
+
+    assert_client_banner_accepted("SSH-2.0-OpenSSH_1.99", 0, 1);
+    assert_int_equal(SSH_VERSION_INT(1, 99, 0), session->openssh);
+    assert_server_banner_accepted("SSH-2.0-OpenSSH_1.99", 0, 1);
+    assert_int_equal(SSH_VERSION_INT(1, 99, 0), session->openssh);
+
+    /* OpenSSH banners: major, minor version limits result in zero */
+    assert_client_banner_accepted("SSH-2.0-OpenSSH_0.99p1", 0, 1);
+    assert_int_equal(0, session->openssh);
+    assert_server_banner_accepted("SSH-2.0-OpenSSH_0.99p1", 0, 1);
+    assert_int_equal(0, session->openssh);
+    assert_client_banner_accepted("SSH-2.0-OpenSSH_1.101p1", 0, 1);
+    assert_int_equal(0, session->openssh);
+    assert_server_banner_accepted("SSH-2.0-OpenSSH_1.101p1", 0, 1);
+    assert_int_equal(0, session->openssh);
+
+    /* OpenSSH banners: bogus major results in zero */
+    assert_client_banner_accepted("SSH-2.0-OpenSSH_X.9p1", 0, 1);
+    assert_int_equal(0, session->openssh);
+    assert_server_banner_accepted("SSH-2.0-OpenSSH_X.9p1", 0, 1);
+    assert_int_equal(0, session->openssh);
+
+    /* OpenSSH banners: bogus minor results in zero */
+    assert_server_banner_accepted("SSH-2.0-OpenSSH_5.Yp1", 0, 1);
+    assert_int_equal(0, session->openssh);
+    assert_client_banner_accepted("SSH-2.0-OpenSSH_5.Yp1", 0, 1);
+    assert_int_equal(0, session->openssh);
+
+    /* OpenSSH banners: ssh-keyscan(1) */
+    assert_client_banner_accepted("SSH-2.0-OpenSSH-keyscan", 0, 1);
+    assert_int_equal(0, session->openssh);
+    assert_server_banner_accepted("SSH-2.0-OpenSSH-keyscan", 0, 1);
+    assert_int_equal(0, session->openssh);
+
+    ssh_free(session);
+}
+
 int torture_run_tests(void) {
     int rc;
     struct CMUnitTest tests[] = {
@@ -221,6 +362,7 @@ int torture_run_tests(void) {
         cmocka_unit_test_setup_teardown(torture_path_expand_known_hosts, setup, teardown),
         cmocka_unit_test(torture_timeout_elapsed),
         cmocka_unit_test(torture_timeout_update),
+        cmocka_unit_test(torture_ssh_analyze_banner),
     };
 
     ssh_init();
diff --git a/tests/unittests/torture_options.c b/tests/unittests/torture_options.c
index 820e607d..296b3f1b 100644
--- a/tests/unittests/torture_options.c
+++ b/tests/unittests/torture_options.c
@@ -200,6 +200,7 @@ static void torture_options_proxycommand(void **state) {
 }
 
 
+#ifdef WITH_SERVER
 /* sshbind options */
 static int sshbind_setup(void **state)
 {
@@ -233,6 +234,7 @@ static void torture_bind_options_import_key(void **state)
     ssh_pki_import_privkey_base64(base64_key, NULL, NULL, NULL, &key);
     rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_IMPORT_KEY, key);
     assert_int_equal(rc, 0);
+#ifdef HAVE_DSA
     /* set dsa key */
     base64_key = torture_get_testkey(SSH_KEYTYPE_DSS, 0, 0);
     ssh_pki_import_privkey_base64(base64_key, NULL, NULL, NULL, &key);
@@ -243,7 +245,9 @@ static void torture_bind_options_import_key(void **state)
     ssh_pki_import_privkey_base64(base64_key, NULL, NULL, NULL, &key);
     rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_IMPORT_KEY, key);
     assert_int_equal(rc, 0);
+#endif
 }
+#endif /* WITH_SERVER */
 
 
 int torture_run_tests(void) {
@@ -261,14 +265,18 @@ int torture_run_tests(void) {
         cmocka_unit_test_setup_teardown(torture_options_proxycommand, setup, teardown),
     };
 
+#ifdef WITH_SERVER
     struct CMUnitTest sshbind_tests[] = {
         cmocka_unit_test_setup_teardown(torture_bind_options_import_key, sshbind_setup, sshbind_teardown),
     };
+#endif /* WITH_SERVER */
 
     ssh_init();
     torture_filter_tests(tests);
     rc = cmocka_run_group_tests(tests, NULL, NULL);
+#ifdef WITH_SERVER
     rc += cmocka_run_group_tests(sshbind_tests, NULL, NULL);
+#endif /* WITH_SERVER */
     ssh_finalize();
     return rc;
 }
diff --git a/tests/unittests/torture_pki.c b/tests/unittests/torture_pki.c
index 8e6e2b63..0b21a569 100644
--- a/tests/unittests/torture_pki.c
+++ b/tests/unittests/torture_pki.c
@@ -6,7 +6,9 @@
 #include <fcntl.h>
 
 #define LIBSSH_RSA_TESTKEY "libssh_testkey.id_rsa"
+#ifdef HAVE_DSA
 #define LIBSSH_DSA_TESTKEY "libssh_testkey.id_dsa"
+#endif
 #define LIBSSH_ECDSA_TESTKEY "libssh_testkey.id_ecdsa"
 #define LIBSSH_ED25519_TESTKEY "libssh_testkey.id_ed25519"
 
@@ -30,6 +32,7 @@ static int setup_rsa_key(void **state)
     return 0;
 }
 
+#ifdef HAVE_DSA
 static int setup_dsa_key(void **state) {
     (void) state; /* unused */
 
@@ -46,6 +49,7 @@ static int setup_dsa_key(void **state) {
 
     return 0;
 }
+#endif
 
 #ifdef HAVE_ECC
 static int setup_ecdsa_key(void **state, int ecdsa_bits) {
@@ -101,7 +105,9 @@ static int setup_both_keys(void **state) {
     (void) state; /* unused */
 
     setup_rsa_key(state);
+#ifdef HAVE_DSA
     setup_dsa_key(state);
+#endif
 
     return 0;
 }
@@ -109,9 +115,11 @@ static int setup_both_keys(void **state) {
 static int teardown(void **state) {
     (void) state; /* unused */
 
+#ifdef HAVE_DSA
     unlink(LIBSSH_DSA_TESTKEY);
     unlink(LIBSSH_DSA_TESTKEY ".pub");
     unlink(LIBSSH_DSA_TESTKEY "-cert.pub");
+#endif
 
     unlink(LIBSSH_RSA_TESTKEY);
     unlink(LIBSSH_RSA_TESTKEY ".pub");
@@ -279,6 +287,7 @@ static void torture_pki_import_privkey_base64_NULL_str(void **state) {
     ssh_key_free(key);
 }
 
+#ifdef HAVE_DSA
 static void torture_pki_import_privkey_base64_DSA(void **state) {
     int rc;
     ssh_key key;
@@ -295,6 +304,7 @@ static void torture_pki_import_privkey_base64_DSA(void **state) {
 
     ssh_key_free(key);
 }
+#endif
 
 #ifdef HAVE_ECC
 static void torture_pki_import_privkey_base64_ECDSA(void **state) {
@@ -347,6 +357,8 @@ static void torture_pki_import_privkey_base64_passphrase(void **state) {
                                        NULL,
                                        &key);
     assert_true(rc == -1);
+    ssh_key_free(key);
+    key = NULL;
 
 #ifndef HAVE_LIBCRYPTO
     /* test if it returns -1 if passphrase is NULL */
@@ -357,7 +369,10 @@ static void torture_pki_import_privkey_base64_passphrase(void **state) {
                                        NULL,
                                        &key);
     assert_true(rc == -1);
+    ssh_key_free(key);
+    key = NULL;
 #endif
+#ifdef HAVE_DSA
 
     /* same for DSA */
 
@@ -382,7 +397,6 @@ static void torture_pki_import_privkey_base64_passphrase(void **state) {
                                        &key);
     assert_true(rc == -1);
 
-#ifndef HAVE_LIBCRYPTO
     /* test if it returns -1 if passphrase is NULL */
     /* libcrypto asks for a passphrase, so skip this test */
     rc = ssh_pki_import_privkey_base64(torture_get_testkey(SSH_KEYTYPE_DSS, 0, 1),
@@ -391,10 +405,8 @@ static void torture_pki_import_privkey_base64_passphrase(void **state) {
                                        NULL,
                                        &key);
     assert_true(rc == -1);
-#endif
-
+# endif
     /* same for ED25519 */
-
     rc = ssh_pki_import_privkey_base64(torture_get_testkey(SSH_KEYTYPE_ED25519, 0, 1),
                                        passphrase,
                                        NULL,
@@ -415,7 +427,6 @@ static void torture_pki_import_privkey_base64_passphrase(void **state) {
                                        NULL,
                                        &key);
     assert_true(rc == -1);
-
 }
 
 static void torture_pki_import_privkey_base64_ed25519(void **state){
@@ -472,6 +483,7 @@ static void torture_pki_pki_publickey_from_privatekey_RSA(void **state) {
     ssh_key_free(pubkey);
 }
 
+#ifdef HAVE_DSA
 static void torture_pki_pki_publickey_from_privatekey_DSA(void **state) {
     int rc;
     ssh_key key;
@@ -496,6 +508,7 @@ static void torture_pki_pki_publickey_from_privatekey_DSA(void **state) {
     ssh_key_free(key);
     ssh_key_free(pubkey);
 }
+#endif
 
 static void torture_pki_pki_publickey_from_privatekey_ed25519(void **state){
     int rc;
@@ -619,6 +632,7 @@ static void torture_pki_import_cert_file_rsa(void **state) {
     ssh_key_free(cert);
 }
 
+#ifdef HAVE_DSA
 static void torture_pki_import_cert_file_dsa(void **state) {
     int rc;
     ssh_key cert;
@@ -674,6 +688,7 @@ static void torture_pki_publickey_dsa_base64(void **state)
     free(key_buf);
     ssh_key_free(key);
 }
+#endif
 
 #ifdef HAVE_ECC
 static void torture_pki_publickey_ecdsa_base64(void **state)
@@ -827,6 +842,7 @@ static void torture_generate_pubkey_from_privkey_rsa(void **state) {
     ssh_key_free(pubkey);
 }
 
+#ifdef HAVE_DSA
 static void torture_generate_pubkey_from_privkey_dsa(void **state) {
     char pubkey_generated[4096] = {0};
     ssh_key privkey;
@@ -865,6 +881,7 @@ static void torture_generate_pubkey_from_privkey_dsa(void **state) {
     ssh_key_free(privkey);
     ssh_key_free(pubkey);
 }
+#endif
 
 static void torture_generate_pubkey_from_privkey_ed25519(void **state){
     char pubkey_generated[4096] = {0};
@@ -995,6 +1012,7 @@ static void torture_pki_duplicate_key_rsa(void **state)
     ssh_string_free_char(b64_key_gen);
 }
 
+#ifdef HAVE_DSA
 static void torture_pki_duplicate_key_dsa(void **state)
 {
     int rc;
@@ -1040,6 +1058,7 @@ static void torture_pki_duplicate_key_dsa(void **state)
     ssh_string_free_char(b64_key);
     ssh_string_free_char(b64_key_gen);
 }
+#endif
 
 #ifdef HAVE_ECC
 static void torture_pki_duplicate_key_ecdsa(void **state)
@@ -1078,8 +1097,11 @@ static void torture_pki_duplicate_key_ecdsa(void **state)
 
     assert_string_equal(b64_key, b64_key_gen);
 
+#ifndef HAVE_LIBMBEDCRYPTO
+    /* libmbedcrypto can't compare ecdsa keys */
     rc = ssh_key_cmp(privkey, privkey_dup, SSH_KEY_CMP_PRIVATE);
     assert_true(rc == 0);
+#endif
 
     ssh_key_free(pubkey);
     ssh_key_free(privkey);
@@ -1210,6 +1232,7 @@ static void torture_pki_generate_key_rsa1(void **state)
     ssh_free(session);
 }
 
+#ifdef HAVE_DSA
 static void torture_pki_generate_key_dsa(void **state)
 {
     int rc;
@@ -1253,6 +1276,7 @@ static void torture_pki_generate_key_dsa(void **state)
 
     ssh_free(session);
 }
+#endif
 
 #ifdef HAVE_ECC
 static void torture_pki_generate_key_ecdsa(void **state)
@@ -1476,6 +1500,8 @@ static void torture_pki_write_privkey_ecdsa(void **state)
 #endif
 #endif /* HAVE_LIBCRYPTO */
 
+#ifdef HAVE_DSA
+/* TODO mbedtls check if rsa can be used instead of dsa */
 static void torture_pki_write_privkey_ed25519(void **state){
     ssh_key origkey;
     ssh_key privkey;
@@ -1541,6 +1567,7 @@ static void torture_pki_write_privkey_ed25519(void **state){
     ssh_key_free(origkey);
     ssh_key_free(privkey);
 }
+#endif
 
 #ifdef HAVE_ECC
 static void torture_pki_ecdsa_name(void **state, const char *expected_name)
@@ -1593,9 +1620,11 @@ int torture_run_tests(void) {
         cmocka_unit_test_setup_teardown(torture_pki_import_privkey_base64_RSA,
                                  setup_rsa_key,
                                  teardown),
+#ifdef HAVE_DSA
         cmocka_unit_test_setup_teardown(torture_pki_import_privkey_base64_DSA,
                                  setup_dsa_key,
                                  teardown),
+#endif
 #ifdef HAVE_ECC
         cmocka_unit_test_setup_teardown(torture_pki_import_privkey_base64_ECDSA,
                                  setup_ecdsa_key_256,
@@ -1615,9 +1644,11 @@ int torture_run_tests(void) {
         cmocka_unit_test_setup_teardown(torture_pki_pki_publickey_from_privatekey_RSA,
                                  setup_rsa_key,
                                  teardown),
+#ifdef HAVE_DSA
         cmocka_unit_test_setup_teardown(torture_pki_pki_publickey_from_privatekey_DSA,
                                  setup_dsa_key,
                                  teardown),
+#endif
 #ifdef HAVE_ECC
         cmocka_unit_test_setup_teardown(torture_pki_publickey_from_privatekey_ECDSA,
                                  setup_ecdsa_key_256,
@@ -1648,6 +1679,7 @@ int torture_run_tests(void) {
         cmocka_unit_test_setup_teardown(torture_pki_import_cert_file_rsa,
                                         setup_rsa_key,
                                         teardown),
+#ifdef HAVE_DSA
         cmocka_unit_test_setup_teardown(torture_pki_import_cert_file_dsa,
                                         setup_dsa_key,
                                         teardown),
@@ -1656,6 +1688,7 @@ int torture_run_tests(void) {
         cmocka_unit_test_setup_teardown(torture_pki_publickey_dsa_base64,
                                  setup_dsa_key,
                                  teardown),
+#endif
         cmocka_unit_test_setup_teardown(torture_pki_publickey_rsa_base64,
                                  setup_rsa_key,
                                  teardown),
@@ -1673,9 +1706,11 @@ int torture_run_tests(void) {
         cmocka_unit_test_setup_teardown(torture_pki_publickey_ed25519_base64,
                                  setup_ed25519_key,
                                  teardown),
+#ifdef HAVE_DSA
         cmocka_unit_test_setup_teardown(torture_generate_pubkey_from_privkey_dsa,
                                  setup_dsa_key,
                                  teardown),
+#endif
         cmocka_unit_test_setup_teardown(torture_generate_pubkey_from_privkey_rsa,
                                  setup_rsa_key,
                                  teardown),
@@ -1696,9 +1731,11 @@ int torture_run_tests(void) {
         cmocka_unit_test_setup_teardown(torture_pki_duplicate_key_rsa,
                                  setup_rsa_key,
                                  teardown),
+#ifdef HAVE_DSA
         cmocka_unit_test_setup_teardown(torture_pki_duplicate_key_dsa,
                                  setup_dsa_key,
                                  teardown),
+#endif
 #ifdef HAVE_ECC
         cmocka_unit_test_setup_teardown(torture_pki_duplicate_key_ecdsa,
                                  setup_ecdsa_key_256,
@@ -1710,12 +1747,16 @@ int torture_run_tests(void) {
                                  setup_ecdsa_key_521,
                                  teardown),
 #endif
+#ifdef HAVE_DSA
         cmocka_unit_test_setup_teardown(torture_pki_duplicate_key_dsa,
                                  setup_dsa_key,
                                  teardown),
+#endif
         cmocka_unit_test(torture_pki_generate_key_rsa),
         cmocka_unit_test(torture_pki_generate_key_rsa1),
+#ifdef HAVE_DSA
         cmocka_unit_test(torture_pki_generate_key_dsa),
+#endif
 #ifdef HAVE_ECC
         cmocka_unit_test(torture_pki_generate_key_ecdsa),
 #endif
@@ -1739,9 +1780,11 @@ int torture_run_tests(void) {
                                  teardown),
 #endif
 #endif /* HAVE_LIBCRYPTO */
+#ifdef HAVE_DSA
         cmocka_unit_test_setup_teardown(torture_pki_write_privkey_ed25519,
                                  setup_dsa_key,
                                  teardown),
+#endif
 
 #ifdef HAVE_ECC
         cmocka_unit_test_setup_teardown(torture_pki_ecdsa_name256,
-- 
2.11.0


Follow-Ups:
Re: [PATCH] add mbedtls crypto supportAndreas Schneider <asn@xxxxxxxxxxxxxx>
Archive administrator: postmaster@lists.cynapses.org