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