aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt11
-rw-r--r--ConfigureChecks.cmake13
-rw-r--r--DefineOptions.cmake1
-rw-r--r--README.mbedtls7
-rw-r--r--cmake/Modules/FindMbedTLS.cmake104
-rw-r--r--config.h.cmake6
-rw-r--r--include/libssh/bignum.h1
-rw-r--r--include/libssh/crypto.h6
-rw-r--r--include/libssh/ecdh.h4
-rw-r--r--include/libssh/keys.h6
-rw-r--r--include/libssh/libmbedcrypto.h111
-rw-r--r--include/libssh/pki.h7
-rw-r--r--include/libssh/wrapper.h1
-rw-r--r--src/CMakeLists.txt19
-rw-r--r--src/bignum.c12
-rw-r--r--src/bind.c4
-rw-r--r--src/curve25519.c8
-rw-r--r--src/dh.c29
-rw-r--r--src/ecdh_mbedcrypto.c295
-rw-r--r--src/kex.c12
-rw-r--r--src/known_hosts.c6
-rw-r--r--src/legacy.c6
-rw-r--r--src/libmbedcrypto.c1122
-rw-r--r--src/mbedcrypto_missing.c128
-rw-r--r--src/misc.c8
-rw-r--r--src/options.c14
-rw-r--r--src/pki.c15
-rw-r--r--src/pki_mbedcrypto.c1304
-rw-r--r--src/server.c2
-rw-r--r--src/session.c2
-rw-r--r--src/threads.c32
-rw-r--r--tests/client/torture_knownhosts.c14
-rw-r--r--tests/pkd/pkd_daemon.c2
-rw-r--r--tests/pkd/pkd_daemon.h2
-rw-r--r--tests/pkd/pkd_hello.c99
-rw-r--r--tests/pkd/pkd_keyutil.c8
-rw-r--r--tests/pkd/pkd_keyutil.h10
-rw-r--r--tests/test_ssh_bind_accept_fd.c8
-rw-r--r--tests/torture.c24
-rw-r--r--tests/unittests/torture_keyfiles.c18
-rw-r--r--tests/unittests/torture_options.c2
-rw-r--r--tests/unittests/torture_pki.c53
42 files changed, 3526 insertions, 10 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b561947b..fbb43524 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 2e1083b4..c589d612 100644
--- a/ConfigureChecks.cmake
+++ b/ConfigureChecks.cmake
@@ -125,7 +125,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)
@@ -133,7 +133,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
@@ -228,6 +232,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..a2a8c5e6 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/README.mbedtls b/README.mbedtls
new file mode 100644
index 00000000..5411f301
--- /dev/null
+++ b/README.mbedtls
@@ -0,0 +1,7 @@
+When built with mbedTLS, libssh currently does not support ECDSA key comparison.
+Since the comparison function is used during the verification of publickey
+authentication requests a libssh server will not be able to deal with ECDSA
+keys.
+
+In general, if the ssh_key_cmp function is used with mbedTLS, ECDSA key
+comparison won't work.
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@sartura.hr>
+#
+# 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 e0460c57..79d18710 100644
--- a/config.h.cmake
+++ b/config.h.cmake
@@ -83,6 +83,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. */
@@ -165,6 +168,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/crypto.h b/include/libssh/crypto.h
index cc54b338..81915e20 100644
--- a/include/libssh/crypto.h
+++ b/include/libssh/crypto.h
@@ -84,6 +84,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;
@@ -135,6 +137,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..f25283ae 100644
--- a/include/libssh/keys.h
+++ b/include/libssh/keys.h
@@ -34,6 +34,9 @@ struct ssh_public_key_struct {
#elif HAVE_LIBCRYPTO
DSA *dsa_pub;
RSA *rsa_pub;
+#elif HAVE_LIBMBEDCRYPTO
+ mbedtls_pk_context *rsa_pub;
+ void *dsa_pub;
#endif
};
@@ -45,6 +48,9 @@ struct ssh_private_key_struct {
#elif defined HAVE_LIBCRYPTO
DSA *dsa_priv;
RSA *rsa_priv;
+#elif HAVE_LIBMBEDCRYPTO
+ mbedtls_pk_context *rsa_priv;
+ void *dsa_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@sartura.hr>
+ *
+ * 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/pki.h b/include/libssh/pki.h
index e0e30f1a..e078768b 100644
--- a/include/libssh/pki.h
+++ b/include/libssh/pki.h
@@ -48,6 +48,10 @@ 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;
+ void *dsa;
#elif HAVE_LIBCRYPTO
DSA *dsa;
RSA *rsa;
@@ -78,6 +82,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/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/bignum.c b/src/bignum.c
index 346a08a8..064006d4 100644
--- a/src/bignum.c
+++ b/src/bignum.c
@@ -60,6 +60,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;
@@ -78,6 +80,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;
@@ -91,6 +96,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
}
@@ -102,6 +109,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);
@@ -109,5 +119,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..7a3e8c93 100644
--- a/src/bind.c
+++ b/src/bind.c
@@ -178,6 +178,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 +200,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,
@@ -450,6 +452,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 +460,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 968af8ce..31b8baec 100644
--- a/src/dh.c
+++ b/src/dh.c
@@ -143,6 +143,8 @@ int ssh_get_random(void *where, int len, int strong){
return RAND_pseudo_bytes(where,len);
}
# endif /* OPENSSL_VERSION_NUMBER */
+#elif defined HAVE_LIBMBEDCRYPTO
+ return ssh_mbedtls_random(where, len, strong);
#endif
/* never reached */
@@ -162,6 +164,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();
@@ -206,7 +210,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;
@@ -228,6 +237,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;
}
@@ -249,6 +260,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 */
@@ -276,6 +289,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 */
@@ -309,6 +324,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
@@ -344,6 +362,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
@@ -430,6 +451,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..d4e7a774
--- /dev/null
+++ b/src/ecdh_mbedcrypto.c
@@ -0,0 +1,295 @@
+/*
+ * This file is part of the SSH Library
+ *
+ * Copyright (c) 2017 Sartura d.o.o.
+ *
+ * Author: Juraj Vijtiuk <juraj.vijtiuk@sartura.hr>
+ *
+ * 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
+
+static mbedtls_ecp_group_id ecdh_kex_type_to_curve(enum ssh_key_exchange_e kex_type) {
+ if (kex_type == SSH_KEX_ECDH_SHA2_NISTP256) {
+ return MBEDTLS_ECP_DP_SECP256R1;
+ } else if (kex_type == SSH_KEX_ECDH_SHA2_NISTP384) {
+ return MBEDTLS_ECP_DP_SECP384R1;
+ } else if (kex_type == SSH_KEX_ECDH_SHA2_NISTP521) {
+ return MBEDTLS_ECP_DP_SECP521R1;
+ }
+
+ return MBEDTLS_ECP_DP_NONE;
+}
+int ssh_client_ecdh_init(ssh_session session)
+{
+ ssh_string client_pubkey = NULL;
+ mbedtls_ecp_group grp;
+ int rc;
+ mbedtls_ecp_group_id curve;
+
+ curve = ecdh_kex_type_to_curve(session->next_crypto->kex_type);
+ if (curve == MBEDTLS_ECP_DP_NONE) {
+ return SSH_ERROR;
+ }
+
+ 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, curve);
+ 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);
+ 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_id curve;
+
+ curve = ecdh_kex_type_to_curve(session->next_crypto->kex_type);
+ if (curve == MBEDTLS_ECP_DP_NONE) {
+ return SSH_ERROR;
+ }
+
+ mbedtls_ecp_group_init(&grp);
+ mbedtls_ecp_point_init(&pubkey);
+
+ rc = mbedtls_ecp_group_load(&grp, curve);
+ 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 = NULL;
+ ssh_string q_s_string = NULL;
+ mbedtls_ecp_group grp;
+ ssh_key privkey = NULL;
+ ssh_string sig_blob = NULL;
+ int rc;
+ mbedtls_ecp_group_id curve;
+
+ curve = ecdh_kex_type_to_curve(session->next_crypto->kex_type);
+ if (curve == MBEDTLS_ECP_DP_NONE) {
+ return SSH_ERROR;
+ }
+
+ 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) {
+ ssh_set_error_oom(session);
+ 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, curve);
+ 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 21523fa9..911f644e 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,ecdh-sha2-nistp384,ecdh-sha2-nistp521,"
#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
@@ -560,7 +570,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 a6bb32f1..2f0584d8 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..139f81b5 100644
--- a/src/legacy.c
+++ b/src/legacy.c
@@ -362,6 +362,9 @@ void publickey_free(ssh_public_key key) {
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:
@@ -463,6 +466,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);
diff --git a/src/libmbedcrypto.c b/src/libmbedcrypto.c
new file mode 100644
index 00000000..6854bd98
--- /dev/null
+++ b/src/libmbedcrypto.c
@@ -0,0 +1,1122 @@
+/*
+ * This file is part of the SSH Library
+ *
+ * Copyright (c) 2017 Sartura d.o.o.
+ *
+ * Author: Juraj Vijtiuk <juraj.vijtiuk@sartura.hr>
+ *
+ * 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/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)
+{
+ mbedtls_ctr_drbg_reseed(&ssh_mbedtls_ctr_drbg, NULL, 0);
+}
+
+SHACTX sha1_init(void)
+{
+ SHACTX ctx = NULL;
+ 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) {
+ SAFE_FREE(ctx);
+ return NULL;
+ }
+
+ rc = mbedtls_md_starts(ctx);
+ if (rc != 0) {
+ SAFE_FREE(ctx);
+ 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 = NULL;
+ 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) {
+ SAFE_FREE(ctx);
+ return NULL;
+ }
+
+ rc = mbedtls_md_starts(ctx);
+ if (rc != 0) {
+ SAFE_FREE(ctx);
+ 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 = NULL;
+ 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) {
+ SAFE_FREE(ctx);
+ return NULL;
+ }
+
+ rc = mbedtls_md_starts(ctx);
+ if (rc != 0) {
+ SAFE_FREE(ctx);
+ 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 = NULL;
+ 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) {
+ SAFE_FREE(ctx);
+ return NULL;
+ }
+
+ rc = mbedtls_md_starts(ctx);
+ if (rc != 0) {
+ SAFE_FREE(ctx);
+ 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 = NULL;
+ 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) {
+ SAFE_FREE(ctx);
+ return NULL;
+ }
+
+ rc = mbedtls_md_starts(ctx);
+ if (rc != 0) {
+ SAFE_FREE(ctx);
+ 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 = NULL;
+ 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) {
+ SAFE_FREE(ctx);
+ return NULL;
+ }
+
+ rc = mbedtls_md_starts(ctx);
+ if (rc != 0) {
+ SAFE_FREE(ctx);
+ 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 = NULL;
+ 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 = NULL;
+ 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 = NULL;
+ 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 = NULL;
+ 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 = NULL;
+ 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);
+ 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 = NULL;
+ 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..44ac7ddc
--- /dev/null
+++ b/src/mbedcrypto_missing.c
@@ -0,0 +1,128 @@
+/*
+ * This file is part of the SSH Library
+ *
+ * Copyright (c) 2017 Sartura d.o.o.
+ *
+ * Author: Juraj Vijtiuk <juraj.vijtiuk@sartura.hr>
+ *
+ * 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/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 == NULL) {
+ 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 fad33294..9ef31184 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -82,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
@@ -349,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;
}
diff --git a/src/options.c b/src/options.c
index d2128c13..14b9e01e 100644
--- a/src/options.c
+++ b/src/options.c
@@ -1493,8 +1493,15 @@ int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type,
key_type = ssh_key_type(key);
switch (key_type) {
case SSH_KEYTYPE_DSS:
+#ifdef HAVE_DSA
bind_key_loc = &sshbind->dsa;
bind_key_path_loc = &sshbind->dsakey;
+#else
+ ssh_set_error(sshbind,
+ SSH_FATAL,
+ "DSS key used and libssh compiled "
+ "without DSA support");
+#endif
break;
case SSH_KEYTYPE_ECDSA:
#ifdef HAVE_ECC
@@ -1550,7 +1557,14 @@ int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type,
key_type = ssh_key_type(key);
switch (key_type) {
case SSH_KEYTYPE_DSS:
+#ifdef HAVE_DSA
bind_key_loc = &sshbind->dsa;
+#else
+ ssh_set_error(sshbind,
+ SSH_FATAL,
+ "DSA key used and libssh compiled "
+ "without DSA support");
+#endif
break;
case SSH_KEYTYPE_ECDSA:
#ifdef HAVE_ECC
diff --git a/src/pki.c b/src/pki.c
index 91f972b1..c362ae24 100644
--- a/src/pki.c
+++ b/src/pki.c
@@ -138,6 +138,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));
@@ -354,6 +364,8 @@ void ssh_signature_free(ssh_signature sig)
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,6 +373,9 @@ 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:
diff --git a/src/pki_mbedcrypto.c b/src/pki_mbedcrypto.c
new file mode 100644
index 00000000..c3508540
--- /dev/null
+++ b/src/pki_mbedcrypto.c
@@ -0,0 +1,1304 @@
+/*
+ * This file is part of the SSH Library
+ *
+ * Copyright (c) 2017 Sartura d.o.o.
+ *
+ * Author: Juraj Vijtiuk <juraj.vijtiuk@sartura.hr>
+ *
+ * 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 != NULL) {
+ mbedtls_pk_free(rsa);
+ SAFE_FREE(rsa);
+ }
+ if (ecdsa != NULL) {
+ 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 = NULL;
+ const mbedtls_pk_info_t *pk_info = NULL;
+ 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 = NULL;
+ int rc;
+ const mbedtls_pk_info_t *pk_info = NULL;
+
+
+ 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) {
+ goto fail;
+ }
+
+ 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) {
+ goto fail;
+ }
+
+ 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:
+ goto fail;
+ }
+
+ 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 = NULL;
+
+ 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:
+ /* TODO: mbedTLS can't compare ecdsa keys.
+ mbedtls_ecdsa_context is actually a mbedtls_ecp_keypair,
+ so the private and public points and the group can be accessed
+ through the keypair. However, mbedtls has no method corresponding
+ to OpenSSL's EC_GROUP_cmp and EC_POITN_cmp, so the comparison
+ would have to be done manually.
+ */
+ 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 = NULL;
+ size_t len = 1;
+ int rc;
+
+ 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_BUFFER_TOO_SMALL) {
+ 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 = NULL;
+ ssh_string type_s = NULL;
+ 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 = NULL;
+ char *n = NULL;
+ int rsa_size = mbedtls_pk_get_bitlen(key->rsa);
+ mbedtls_rsa_context *rsa = NULL;
+
+ 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 = NULL;
+ char *blob_padded_data = NULL;
+ ssh_string sig_blob_padded = NULL;
+
+ 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 = NULL;
+ 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 = NULL;
+ unsigned char *sig = NULL;
+ 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 = NULL;
+ 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 = NULL;
+ 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;
+}
+
+int pki_pubkey_build_dss(ssh_key key, ssh_string p, ssh_string q, ssh_string g,
+ ssh_string pubkey)
+{
+ (void) key;
+ (void) p;
+ (void) q;
+ (void) g;
+ (void) pubkey;
+ return SSH_ERROR;
+}
+
+int pki_key_generate_dss(ssh_key key, int parameter)
+{
+ (void) key;
+ (void) parameter;
+ return SSH_ERROR;
+}
+#endif /* HAVE_LIBMBEDCRYPTO */
diff --git a/src/server.c b/src/server.c
index b2552eaa..b31a8e42 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);
diff --git a/src/session.c b/src/session.c
index bb01f169..b372dad6 100644
--- a/src/session.c
+++ b/src/session.c
@@ -148,6 +148,7 @@ ssh_session ssh_new(void) {
goto err;
}
+#ifdef HAVE_DSA
id = strdup("%d/id_dsa");
if (id == NULL) {
goto err;
@@ -156,6 +157,7 @@ ssh_session ssh_new(void) {
if (rc == SSH_ERROR) {
goto err;
}
+#endif
id = strdup("%d/identity");
if (id == NULL) {
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/tests/client/torture_knownhosts.c b/tests/client/torture_knownhosts.c
index 1702b467..cfa47deb 100644
--- a/tests/client/torture_knownhosts.c
+++ b/tests/client/torture_knownhosts.c
@@ -40,6 +40,7 @@
"YgIytryNn7LLiwYfoSxvWigFrTTZsrVtCOYyNgklmffpGdzuC43wdANvTewfI9G" \
"o71r8EXmEc228CrYPmb8Scv3mpXFK/BosohSGkPlEHu9lf3YjnknBicDaVtJOYp" \
"wnXJPjZo2EhG79HxDRpjJHH"
+#ifdef HAVE_DSA
#define BADDSA "AAAAB3NzaC1kc3MAAACBAITDKqGQ5aC5wHySG6ZdL1+BVBY2nLP5vzw3i3pvZfP" \
"yNUS0UCwrt5pajsMvDRGXXebTJhWVonDnv8tpSgiuIBXMZrma8CU1KCFGRzwb/n8" \
"cc5tJmIphlOUTrObjBmsRz7u1eZmoaddXC9ask6BNnt0DmhzYi2esL3mbardy8IN" \
@@ -50,6 +51,7 @@
"EcxqLVllrNEvd2EGD9p16BYO2yaalYon8im59PtOcul2ay5XQ6rVDQ2T0pgNUpsI" \
"h0dSi8VJXI1wes5HTyLsv9VBmU1uCXUUvufoQKfF/OcSH0ufcCpnd62g1/adZcy2" \
"WJg=="
+#endif
static int sshd_setup(void **state)
{
@@ -187,6 +189,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;
@@ -272,6 +275,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;
@@ -298,7 +302,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);
@@ -356,15 +362,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);
}
@@ -378,12 +390,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 9860ca56..a128c8e9 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 7f553fdf..3107ed1e 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 4db8ee5c..e0c0cbf6 100644
--- a/tests/pkd/pkd_hello.c
+++ b/tests/pkd/pkd_hello.c
@@ -146,12 +146,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();
@@ -178,6 +180,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) \
@@ -185,7 +188,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@libssh.org"), setup_rsa, teardown) \
@@ -218,7 +230,28 @@ static int torture_pkd_setup_ecdsa_521(void **state) {
f(client, ecdsa_521_ecdh_sha2_nistp521, kexcmd("ecdh-sha2-nistp521 "), 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@libssh.org"), 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@libssh.org"), 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@libssh.org"), 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@libssh.org"), 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) \
@@ -251,7 +284,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_OPENSSHONLY(f, client, ciphercmd) \
/* Ciphers. */ \
f(client, rsa_aes192_cbc, ciphercmd("aes192-cbc"), setup_rsa, teardown) \
@@ -264,7 +326,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_OPENSSHONLY(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) \
@@ -282,6 +357,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);
@@ -328,6 +419,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)
@@ -335,6 +427,7 @@ PKDTESTS_CIPHER(emit_keytest, openssh_dsa, OPENSSH_CIPHER_CMD)
PKDTESTS_CIPHER_OPENSSHONLY(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)
@@ -393,11 +486,13 @@ struct {
const struct CMUnitTest test;
} 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_OPENSSHONLY(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)
@@ -438,11 +533,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_OPENSSHONLY(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)
@@ -546,7 +643,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 8486eb41..26f15ce0 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:
@@ -862,7 +872,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];
@@ -882,7 +894,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"
@@ -901,8 +915,12 @@ 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"
-# if (OPENSSH_VERSION_MAJOR == 7 && OPENSSH_VERSION_MINOR < 6)
+# else
+ "HostKeyAlgorithms +ssh-rsa\n"
+# endif
+# if (OPENSSH_VERSION_MAJOR == 7 && OPENSSH_VERSION_MINOR < 6)
"Ciphers +3des-cbc,aes128-cbc,aes192-cbc,aes256-cbc,blowfish-cbc\n"
# else
"Ciphers +3des-cbc,aes128-cbc,aes192-cbc,aes256-cbc\n"
@@ -939,11 +957,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),
@@ -980,7 +1000,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 023396e7..ea456050 100644
--- a/tests/unittests/torture_keyfiles.c
+++ b/tests/unittests/torture_keyfiles.c
@@ -6,7 +6,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)
{
@@ -26,6 +28,7 @@ static int setup_rsa_key(void **state)
return 0;
}
+#ifdef HAVE_DSA
static int setup_dsa_key(void **state)
{
ssh_session session;
@@ -43,6 +46,7 @@ static int setup_dsa_key(void **state)
return 0;
}
+#endif
static int setup_both_keys(void **state) {
int rc;
@@ -51,9 +55,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;
}
@@ -67,10 +73,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;
@@ -80,8 +88,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");
@@ -216,12 +226,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);
@@ -231,12 +243,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
}
/**
@@ -253,12 +267,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);
@@ -268,12 +284,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_options.c b/tests/unittests/torture_options.c
index 66348147..0203ab67 100644
--- a/tests/unittests/torture_options.c
+++ b/tests/unittests/torture_options.c
@@ -366,11 +366,13 @@ 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);
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_IMPORT_KEY, key);
assert_int_equal(rc, 0);
+#endif
/* set ecdsa key */
base64_key = torture_get_testkey(SSH_KEYTYPE_ECDSA, 512, 0);
ssh_pki_import_privkey_base64(base64_key, NULL, NULL, NULL, &key);
diff --git a/tests/unittests/torture_pki.c b/tests/unittests/torture_pki.c
index b0e6840c..33e7cd89 100644
--- a/tests/unittests/torture_pki.c
+++ b/tests/unittests/torture_pki.c
@@ -8,7 +8,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"
@@ -32,6 +34,7 @@ static int setup_rsa_key(void **state)
return 0;
}
+#ifdef HAVE_DSA
static int setup_dsa_key(void **state) {
(void) state; /* unused */
@@ -48,6 +51,7 @@ static int setup_dsa_key(void **state) {
return 0;
}
+#endif
#ifdef HAVE_ECC
static int setup_ecdsa_key(void **state, int ecdsa_bits) {
@@ -103,7 +107,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;
}
@@ -111,9 +117,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");
@@ -281,6 +289,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;
@@ -297,6 +306,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) {
@@ -349,6 +359,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 */
@@ -359,7 +371,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 */
@@ -384,7 +399,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),
@@ -393,10 +407,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,
@@ -417,7 +429,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){
@@ -474,6 +485,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;
@@ -498,6 +510,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;
@@ -621,6 +634,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;
@@ -676,6 +690,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)
@@ -829,6 +844,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;
@@ -867,6 +883,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};
@@ -997,6 +1014,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;
@@ -1042,6 +1060,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)
@@ -1080,8 +1099,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);
@@ -1212,6 +1234,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;
@@ -1255,6 +1278,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)
@@ -1478,6 +1502,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;
@@ -1543,6 +1569,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)
@@ -1595,9 +1622,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,
@@ -1617,9 +1646,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,
@@ -1650,6 +1681,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),
@@ -1658,6 +1690,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),
@@ -1675,9 +1708,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),
@@ -1698,9 +1733,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,
@@ -1712,12 +1749,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
@@ -1741,9 +1782,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,