diff options
42 files changed, 3526 insertions, 10 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index b561947b..fbb43524 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,12 +49,20 @@ if (WITH_GCRYPT) if (NOT GCRYPT_FOUND) message(FATAL_ERROR "Could not find GCrypt") endif (NOT GCRYPT_FOUND) +elseif(WITH_MBEDTLS) + find_package(MbedTLS REQUIRED) + if (NOT MBEDTLS_FOUND) + message(FATAL_ERROR "Could not find mbedTLS") + endif (NOT MBEDTLS_FOUND) else (WITH_GCRYPT) find_package(OpenSSL) if (NOT OPENSSL_FOUND) find_package(GCrypt) if (NOT GCRYPT_FOUND) - message(FATAL_ERROR "Could not find OpenSSL or GCrypt") + find_package(MbedTLS) + if (NOT MBEDTLS_FOUND) + message(FATAL_ERROR "Could not find OpenSSL, GCrypt or mbedTLS") + endif (NOT MBEDTLS_FOUND) endif (NOT GCRYPT_FOUND) endif (NOT OPENSSL_FOUND) endif(WITH_GCRYPT) @@ -150,6 +158,7 @@ message(STATUS "********** ${PROJECT_NAME} build options : **********") message(STATUS "zlib support: ${WITH_ZLIB}") message(STATUS "libgcrypt support: ${WITH_GCRYPT}") +message(STATUS "libmbedTLS support: ${WITH_MBEDTLS}") message(STATUS "libnacl support: ${WITH_NACL}") message(STATUS "SSH-1 support: ${WITH_SSH1}") message(STATUS "SFTP support: ${WITH_SFTP}") diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake index 2e1083b4..c589d612 100644 --- a/ConfigureChecks.cmake +++ b/ConfigureChecks.cmake @@ -125,7 +125,7 @@ if (CMAKE_HAVE_PTHREAD_H) set(HAVE_PTHREAD_H 1) endif (CMAKE_HAVE_PTHREAD_H) -if (NOT WITH_GCRYPT) +if (NOT WITH_GCRYPT AND NOT WITH_MBEDTLS) if (HAVE_OPENSSL_EC_H AND HAVE_OPENSSL_ECDSA_H) set(HAVE_OPENSSL_ECC 1) endif (HAVE_OPENSSL_EC_H AND HAVE_OPENSSL_ECDSA_H) @@ -133,7 +133,11 @@ if (NOT WITH_GCRYPT) if (HAVE_OPENSSL_ECC) set(HAVE_ECC 1) endif (HAVE_OPENSSL_ECC) -endif (NOT WITH_GCRYPT) +endif () + +if (NOT WITH_MBEDTLS) + set(HAVE_DSA 1) +endif() # FUNCTIONS @@ -228,6 +232,11 @@ if (GCRYPT_FOUND) endif (GCRYPT_VERSION VERSION_GREATER "1.4.6") endif (GCRYPT_FOUND) +if (MBEDTLS_FOUND) + set(HAVE_LIBMBEDCRYPTO 1) + set(HAVE_ECC 1) +endif (MBEDTLS_FOUND) + if (CMAKE_USE_PTHREADS_INIT) set(HAVE_PTHREAD 1) endif (CMAKE_USE_PTHREADS_INIT) diff --git a/DefineOptions.cmake b/DefineOptions.cmake index ab7819a5..a2a8c5e6 100644 --- a/DefineOptions.cmake +++ b/DefineOptions.cmake @@ -7,6 +7,7 @@ option(WITH_STATIC_LIB "Build with a static library" OFF) option(WITH_DEBUG_CRYPTO "Build with cryto debug output" OFF) option(WITH_DEBUG_CALLTRACE "Build with calltrace debug output" ON) option(WITH_GCRYPT "Compile against libgcrypt" OFF) +option(WITH_MBEDTLS "Compile against libmbedtls" OFF) option(WITH_PCAP "Compile with Pcap generation support" ON) option(WITH_INTERNAL_DOC "Compile doxygen internal documentation" OFF) option(WITH_TESTING "Build with unit tests" OFF) diff --git a/README.mbedtls b/README.mbedtls new file mode 100644 index 00000000..5411f301 --- /dev/null +++ b/README.mbedtls @@ -0,0 +1,7 @@ +When built with mbedTLS, libssh currently does not support ECDSA key comparison. +Since the comparison function is used during the verification of publickey +authentication requests a libssh server will not be able to deal with ECDSA +keys. + +In general, if the ssh_key_cmp function is used with mbedTLS, ECDSA key +comparison won't work. diff --git a/cmake/Modules/FindMbedTLS.cmake b/cmake/Modules/FindMbedTLS.cmake new file mode 100644 index 00000000..baec8adc --- /dev/null +++ b/cmake/Modules/FindMbedTLS.cmake @@ -0,0 +1,104 @@ +# - Try to find mbedTLS +# Once done this will define +# +# MBEDTLS_FOUND - system has mbedTLS +# MBEDTLS_INCLUDE_DIRS - the mbedTLS include directory +# MBEDTLS_LIBRARIES - Link these to use mbedTLS +# MBEDTLS_DEFINITIONS - Compiler switches required for using mbedTLS +#============================================================================= +# Copyright (c) 2017 Sartura d.o.o. +# +# Author: Juraj Vijtiuk <juraj.vijtiuk@sartura.hr> +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# + + +set(_MBEDTLS_ROOT_HINTS + $ENV{MBEDTLS_ROOT_DIR} + ${MBEDTLS_ROOT_DIR}) + +set(_MBEDTLS_ROOT_PATHS + "$ENV{PROGRAMFILES}/libmbedtls") + +set(_MBEDTLS_ROOT_HINTS_AND_PATHS + HINTS ${_MBEDTLS_ROOT_HINTS} + PATHS ${_MBEDTLS_ROOT_PATHS}) + + +find_path(MBEDTLS_INCLUDE_DIR + NAMES + mbedtls/config.h + HINTS + ${_MBEDTLS_ROOT_HINTS_AND_PATHS} + PATH_SUFFIXES + include +) + +find_library(MBEDTLS_SSL_LIBRARY + NAMES + mbedtls + HINTS + ${_MBEDTLS_ROOT_HINTS_AND_PATHS} + PATH_SUFFIXES + lib + +) + +find_library(MBEDTLS_CRYPTO_LIBRARY + NAMES + mbedcrypto + HINTS + ${_MBEDTLS_ROOT_HINTS_AND_PATHS} + PATH_SUFFIXES + lib +) + +find_library(MBEDTLS_X509_LIBRARY + NAMES + mbedx509 + HINTS + ${_MBEDTLS_ROOT_HINTS_AND_PATHS} + PATH_SUFFIXES + lib +) + +set(MBEDTLS_LIBRARIES ${MBEDTLS_SSL_LIBRARY} ${MBEDTLS_CRYPTO_LIBRARY} + ${MBEDTLS_X509_LIBRARY}) + +if (MBEDTLS_INCLUDE_DIR AND EXISTS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h") + file(STRINGS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h" _mbedtls_version_str REGEX + "^#[\t ]*define[\t ]+MBEDTLS_VERSION_STRING[\t ]+\"[0-9]+.[0-9]+.[0-9]+\"") + + string(REGEX REPLACE "^.*MBEDTLS_VERSION_STRING.*([0-9]+.[0-9]+.[0-9]+).*" + "\\1" MBEDTLS_VERSION "${_mbedtls_version_str}") +endif () + +include(FindPackageHandleStandardArgs) +if (MBEDTLS_VERSION) + find_package_handle_standard_args(MbedTLS + REQUIRED_VARS + MBEDTLS_INCLUDE_DIR + MBEDTLS_LIBRARIES + VERSION_VAR + MBEDTLS_VERSION + FAIL_MESSAGE + "Could NOT find mbedTLS, try to set the path to mbedTLS root folder + in the system variable MBEDTLS_ROOT_DIR" + ) +else (MBEDTLS_VERSION) + find_package_handle_standard_args(MBedTLS + "Could NOT find mbedTLS, try to set the path to mbedLS root folder in + the system variable MBEDTLS_ROOT_DIR" + MBEDTLS_INCLUDE_DIR + MBEDTLS_LIBRARIES) +endif (MBEDTLS_VERSION) + +# show the MBEDTLS_INCLUDE_DIRS and MBEDTLS_LIBRARIES variables only in the advanced view +mark_as_advanced(MBEDTLS_INCLUDE_DIR MBEDTLS_LIBRARIES) diff --git a/config.h.cmake b/config.h.cmake index e0460c57..79d18710 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -83,6 +83,9 @@ /* Define to 1 if you have eliptic curve cryptography */ #cmakedefine HAVE_ECC 1 +/* Define to 1 if you have DSA */ +#cmakedefine HAVE_DSA 1 + /*************************** FUNCTIONS ***************************/ /* Define to 1 if you have the `EVP_aes128_ctr' function. */ @@ -165,6 +168,9 @@ /* Define to 1 if you have the `gcrypt' library (-lgcrypt). */ #cmakedefine HAVE_LIBGCRYPT 1 +/* Define to 1 if you have the 'mbedTLS' library (-lmbedtls). */ +#cmakedefine HAVE_LIBMBEDCRYPTO 1 + /* Define to 1 if you have the `pthread' library (-lpthread). */ #cmakedefine HAVE_PTHREAD 1 diff --git a/include/libssh/bignum.h b/include/libssh/bignum.h index 71970e3e..32727050 100644 --- a/include/libssh/bignum.h +++ b/include/libssh/bignum.h @@ -23,6 +23,7 @@ #include "libssh/libcrypto.h" #include "libssh/libgcrypt.h" +#include "libssh/libmbedcrypto.h" bignum ssh_make_string_bn(ssh_string string); void ssh_make_string_bn_inplace(ssh_string string, bignum bnout); diff --git a/include/libssh/crypto.h b/include/libssh/crypto.h index cc54b338..81915e20 100644 --- a/include/libssh/crypto.h +++ b/include/libssh/crypto.h @@ -84,6 +84,8 @@ struct ssh_crypto_struct { EC_KEY *ecdh_privkey; #elif defined HAVE_GCRYPT_ECC gcry_sexp_t ecdh_privkey; +#elif defined HAVE_LIBMBEDCRYPTO + mbedtls_ecp_keypair *ecdh_privkey; #endif ssh_string ecdh_client_pubkey; ssh_string ecdh_server_pubkey; @@ -135,6 +137,10 @@ struct ssh_cipher_struct { struct ssh_aes_key_schedule *aes_key; const EVP_CIPHER *cipher; EVP_CIPHER_CTX *ctx; +#elif defined HAVE_LIBMBEDCRYPTO + mbedtls_cipher_context_t encrypt_ctx; + mbedtls_cipher_context_t decrypt_ctx; + mbedtls_cipher_type_t type; #endif unsigned int keysize; /* bytes of key used. != keylen */ /* sets the new key for immediate use */ diff --git a/include/libssh/ecdh.h b/include/libssh/ecdh.h index 9f94d69c..66659b85 100644 --- a/include/libssh/ecdh.h +++ b/include/libssh/ecdh.h @@ -37,6 +37,10 @@ #define HAVE_ECDH 1 #endif +#ifdef HAVE_LIBMBEDCRYPTO +#define HAVE_ECDH 1 +#endif + /* Common functions. */ int ssh_client_ecdh_reply(ssh_session session, ssh_buffer packet); diff --git a/include/libssh/keys.h b/include/libssh/keys.h index 6f08e070..f25283ae 100644 --- a/include/libssh/keys.h +++ b/include/libssh/keys.h @@ -34,6 +34,9 @@ struct ssh_public_key_struct { #elif HAVE_LIBCRYPTO DSA *dsa_pub; RSA *rsa_pub; +#elif HAVE_LIBMBEDCRYPTO + mbedtls_pk_context *rsa_pub; + void *dsa_pub; #endif }; @@ -45,6 +48,9 @@ struct ssh_private_key_struct { #elif defined HAVE_LIBCRYPTO DSA *dsa_priv; RSA *rsa_priv; +#elif HAVE_LIBMBEDCRYPTO + mbedtls_pk_context *rsa_priv; + void *dsa_priv; #endif }; diff --git a/include/libssh/libmbedcrypto.h b/include/libssh/libmbedcrypto.h new file mode 100644 index 00000000..7cc1bbb0 --- /dev/null +++ b/include/libssh/libmbedcrypto.h @@ -0,0 +1,111 @@ +/* + * This file is part of the SSH Library + * + * Copyright (c) 2017 Sartura d.o.o. + * + * Author: Juraj Vijtiuk <juraj.vijtiuk@sartura.hr> + * + * The SSH Library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * The SSH Library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the SSH Library; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +#ifndef LIBMBEDCRYPTO_H_ +#define LIBMBEDCRYPTO_H_ + +#include "config.h" + +#ifdef HAVE_LIBMBEDCRYPTO + +#include <mbedtls/md.h> +#include <mbedtls/bignum.h> +#include <mbedtls/pk.h> +#include <mbedtls/cipher.h> +#include <mbedtls/entropy.h> +#include <mbedtls/ctr_drbg.h> + +typedef mbedtls_md_context_t *SHACTX; +typedef mbedtls_md_context_t *SHA256CTX; +typedef mbedtls_md_context_t *SHA384CTX; +typedef mbedtls_md_context_t *SHA512CTX; +typedef mbedtls_md_context_t *MD5CTX; +typedef mbedtls_md_context_t *HMACCTX; +typedef mbedtls_md_context_t *EVPCTX; + +#define SHA_DIGEST_LENGTH 20 +#define SHA_DIGEST_LEN SHA_DIGEST_LENGTH +#define MD5_DIGEST_LEN 16 +#define SHA256_DIGEST_LENGTH 32 +#define SHA256_DIGEST_LEN SHA256_DIGEST_LENGTH +#define SHA384_DIGEST_LENGTH 48 +#define SHA384_DIGEST_LEN SHA384_DIGEST_LENGTH +#define SHA512_DIGEST_LENGTH 64 +#define SHA512_DIGEST_LEN SHA512_DIGEST_LENGTH + +#ifndef EVP_MAX_MD_SIZE +#define EVP_MAX_MD_SIZE 64 +#endif + +#define EVP_DIGEST_LEN EVP_MAX_MD_SIZE + +typedef mbedtls_mpi *bignum; + +/* Constants for curves */ +#define NID_mbedtls_nistp256 0 +#define NID_mbedtls_nistp384 1 +#define NID_mbedtls_nistp521 2 + +struct mbedtls_ecdsa_sig { + bignum r; + bignum s; +}; + +bignum ssh_mbedcry_bn_new(void); +void ssh_mbedcry_bn_free(bignum num); +char *ssh_mbedcry_bn2num(bignum num, int radix); +int ssh_mbedcry_rand(bignum rnd, int bits, int top, int bottom); +int ssh_mbedcry_is_bit_set(bignum num, size_t pos); + +#define bignum_new() ssh_mbedcry_bn_new() +#define bignum_free(num) ssh_mbedcry_bn_free(num); +#define bignum_set_word(bn, n) mbedtls_mpi_lset(bn, n) /* TODO fix + overflow/underflow */ +#define bignum_bin2bn(data, datalen, bn) mbedtls_mpi_read_binary(bn, data, \ + datalen) +#define bignum_bn2dec(num) ssh_mbedcry_bn2num(num, 10) +#define bignum_dec2bn(data, bn) mbedtls_mpi_read_string(bn, 10, data) +#define bignum_bn2hex(num) ssh_mbedcry_bn2num(num, 16) +#define bignum_rand(rnd, bits, top, bottom) ssh_mbedcry_rand(rnd, bits, \ + top, bottom) +#define bignum_mod_exp(dest, generator, exp, modulo, ctx) \ + mbedtls_mpi_exp_mod(dest, generator, exp, modulo, NULL) +#define bignum_num_bytes(num) mbedtls_mpi_size(num) +#define bignum_num_bits(num) mbedtls_mpi_bitlen(num) +#define bignum_is_bit_set(num, bit) ssh_mbedcry_is_bit_set(num, bit) +#define bignum_bn2bin(num, ptr) mbedtls_mpi_write_binary(num, ptr, \ + mbedtls_mpi_size(num)) +#define bignum_cmp(num1, num2) mbedtls_mpi_cmp_mpi(num1, num2) + +mbedtls_entropy_context ssh_mbedtls_entropy; +mbedtls_ctr_drbg_context ssh_mbedtls_ctr_drbg; + +void ssh_mbedtls_init(void); +void ssh_mbedtls_cleanup(void); +int ssh_mbedtls_random(void *where, int len, int strong); + +ssh_string make_ecpoint_string(const mbedtls_ecp_group *g, const + mbedtls_ecp_point *p); + +#endif /* HAVE_LIBMBEDCRYPTO */ +#endif /* LIBMBEDCRYPTO_H_ */ diff --git a/include/libssh/pki.h b/include/libssh/pki.h index e0e30f1a..e078768b 100644 --- a/include/libssh/pki.h +++ b/include/libssh/pki.h @@ -48,6 +48,10 @@ struct ssh_key_struct { gcry_sexp_t dsa; gcry_sexp_t rsa; gcry_sexp_t ecdsa; +#elif HAVE_LIBMBEDCRYPTO + mbedtls_pk_context *rsa; + mbedtls_ecdsa_context *ecdsa; + void *dsa; #elif HAVE_LIBCRYPTO DSA *dsa; RSA *rsa; @@ -78,6 +82,9 @@ struct ssh_signature_struct { # else void *ecdsa_sig; # endif +#elif defined HAVE_LIBMBEDCRYPTO + ssh_string rsa_sig; + struct mbedtls_ecdsa_sig ecdsa_sig; #endif ed25519_signature *ed25519_sig; }; diff --git a/include/libssh/wrapper.h b/include/libssh/wrapper.h index cdd72d6d..6b6cf0b1 100644 --- a/include/libssh/wrapper.h +++ b/include/libssh/wrapper.h @@ -25,6 +25,7 @@ #include "libssh/libssh.h" #include "libssh/libcrypto.h" #include "libssh/libgcrypt.h" +#include "libssh/libmbedcrypto.h" enum ssh_mac_e { SSH_MAC_SHA1=1, diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e5a93538..da87313e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -39,6 +39,17 @@ if (OPENSSL_CRYPTO_LIBRARY) ) endif (OPENSSL_CRYPTO_LIBRARY) +if (MBEDTLS_CRYPTO_LIBRARY) + set(LIBSSH_PRIVATE_INCLUDE_DIRS + ${LIBSSH_PRIVATE_INCLUDE_DIRS} + ${MBEDTLS_INCLUDE_DIR} + ) + set(LIBSSH_LINK_LIBRARIES + ${LIBSSH_LINK_LIBRARIES} + ${MBEDTLS_CRYPTO_LIBRARY} + ) +endif (MBEDTLS_CRYPTO_LIBRARY) + if (GCRYPT_LIBRARY) set(LIBSSH_PRIVATE_INCLUDE_DIRS ${LIBSSH_PRIVATE_INCLUDE_DIRS} @@ -160,6 +171,14 @@ if (WITH_GCRYPT) pki_gcrypt.c ecdh_gcrypt.c ) +elseif (WITH_MBEDTLS) + set(libssh_SRCS + ${libssh_SRCS} + libmbedcrypto.c + mbedcrypto_missing.c + pki_mbedcrypto.c + ecdh_mbedcrypto.c + ) else (WITH_GCRYPT) set(libssh_SRCS ${libssh_SRCS} diff --git a/src/bignum.c b/src/bignum.c index 346a08a8..064006d4 100644 --- a/src/bignum.c +++ b/src/bignum.c @@ -60,6 +60,8 @@ ssh_string ssh_make_bignum_string(bignum num) { bignum_bn2bin(num, len, ptr->data + pad); #elif HAVE_LIBCRYPTO bignum_bn2bin(num, ptr->data + pad); +#elif HAVE_LIBMBEDCRYPTO + bignum_bn2bin(num, ptr->data + pad); #endif return ptr; @@ -78,6 +80,9 @@ bignum ssh_make_string_bn(ssh_string string){ bignum_bin2bn(string->data, len, &bn); #elif defined HAVE_LIBCRYPTO bn = bignum_bin2bn(string->data, len, NULL); +#elif defined HAVE_LIBMBEDCRYPTO + bn = bignum_new(); + bignum_bin2bn(string->data, len, bn); #endif return bn; @@ -91,6 +96,8 @@ void ssh_make_string_bn_inplace(ssh_string string, bignum bnout) { (void) bnout; #elif defined HAVE_LIBCRYPTO bignum_bin2bn(string->data, len, bnout); +#elif defined HAVE_LIBMBEDCRYPTO + bignum_bin2bn(string->data, len, bnout); #endif } @@ -102,6 +109,9 @@ void ssh_print_bignum(const char *which, const bignum num) { #elif defined HAVE_LIBCRYPTO char *hex = NULL; hex = bignum_bn2hex(num); +#elif defined HAVE_LIBMBEDCRYPTO + char *hex = NULL; + hex = bignum_bn2hex(num); #endif fprintf(stderr, "%s value: ", which); fprintf(stderr, "%s\n", (hex == NULL) ? "(null)" : (char *) hex); @@ -109,5 +119,7 @@ void ssh_print_bignum(const char *which, const bignum num) { SAFE_FREE(hex); #elif defined HAVE_LIBCRYPTO OPENSSL_free(hex); +#elif defined HAVE_LIBMBEDCRYPTO + SAFE_FREE(hex); #endif } @@ -178,6 +178,7 @@ static int ssh_bind_import_keys(ssh_bind sshbind) { } #endif +#ifdef HAVE_DSA if (sshbind->dsa == NULL && sshbind->dsakey != NULL) { rc = ssh_pki_import_privkey_file(sshbind->dsakey, NULL, @@ -199,6 +200,7 @@ static int ssh_bind_import_keys(ssh_bind sshbind) { return SSH_ERROR; } } +#endif if (sshbind->rsa == NULL && sshbind->rsakey != NULL) { rc = ssh_pki_import_privkey_file(sshbind->rsakey, @@ -450,6 +452,7 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd){ } } #endif +#ifdef HAVE_DSA if (sshbind->dsa) { session->srv.dsa_key = ssh_key_dup(sshbind->dsa); if (session->srv.dsa_key == NULL) { @@ -457,6 +460,7 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd){ return SSH_ERROR; } } +#endif if (sshbind->rsa) { session->srv.rsa_key = ssh_key_dup(sshbind->rsa); if (session->srv.rsa_key == NULL) { diff --git a/src/curve25519.c b/src/curve25519.c index 77fab2d2..6d9a409c 100644 --- a/src/curve25519.c +++ b/src/curve25519.c @@ -78,6 +78,12 @@ static int ssh_curve25519_build_k(ssh_session session) { if (session->next_crypto->k == NULL) { return SSH_ERROR; } +#elif defined HAVE_LIBMBEDCRYPTO + session->next_crypto->k = bignum_new(); + + if (session->next_crypto->k == NULL) { + return SSH_ERROR; + } #endif if (session->server) @@ -91,6 +97,8 @@ static int ssh_curve25519_build_k(ssh_session session) { bignum_bin2bn(k, CURVE25519_PUBKEY_SIZE, &session->next_crypto->k); #elif defined HAVE_LIBCRYPTO bignum_bin2bn(k, CURVE25519_PUBKEY_SIZE, session->next_crypto->k); +#elif defined HAVE_LIBMBEDCRYPTO + bignum_bin2bn(k, CURVE25519_PUBKEY_SIZE, session->next_crypto->k); #endif #ifdef DEBUG_CRYPTO @@ -143,6 +143,8 @@ int ssh_get_random(void *where, int len, int strong){ return RAND_pseudo_bytes(where,len); } # endif /* OPENSSL_VERSION_NUMBER */ +#elif defined HAVE_LIBMBEDCRYPTO + return ssh_mbedtls_random(where, len, strong); #endif /* never reached */ @@ -162,6 +164,8 @@ int ssh_crypto_init(void) { gcry_control(GCRYCTL_INIT_SECMEM, 4096); gcry_control(GCRYCTL_INITIALIZATION_FINISHED,0); } +#elif HAVE_LIBMBEDCRYPTO + ssh_mbedtls_init(); #endif g = bignum_new(); @@ -206,7 +210,12 @@ int ssh_crypto_init(void) { bignum_bin2bn(p_group14_value, P_GROUP14_LEN, p_group14); OpenSSL_add_all_algorithms(); +#elif defined HAVE_LIBMBEDCRYPTO + p_group1 = bignum_new(); + bignum_bin2bn(p_group1_value, P_GROUP1_LEN, p_group1); + p_group14 = bignum_new(); + bignum_bin2bn(p_group14_value, P_GROUP14_LEN, p_group14); #endif ssh_crypto_initialized = 1; @@ -228,6 +237,8 @@ void ssh_crypto_finalize(void) { #elif defined HAVE_LIBCRYPTO EVP_cleanup(); CRYPTO_cleanup_all_ex_data(); +#elif defined HAVE_LIBMBEDTLS + ssh_mbedtls_cleanup(); #endif ssh_crypto_initialized=0; } @@ -249,6 +260,8 @@ int ssh_dh_generate_x(ssh_session session) { bignum_rand(session->next_crypto->x, keysize); #elif defined HAVE_LIBCRYPTO bignum_rand(session->next_crypto->x, keysize, -1, 0); +#elif defined HAVE_LIBMBEDCRYPTO + bignum_rand(session->next_crypto->x, keysize, -1, 0); #endif /* not harder than this */ @@ -276,6 +289,8 @@ int ssh_dh_generate_y(ssh_session session) { bignum_rand(session->next_crypto->y, keysize); #elif defined HAVE_LIBCRYPTO bignum_rand(session->next_crypto->y, keysize, -1, 0); +#elif defined HAVE_LIBMBEDCRYPTO + bignum_rand(session->next_crypto->y, keysize, -1, 0); #endif /* not harder than this */ @@ -309,6 +324,9 @@ int ssh_dh_generate_e(ssh_session session) { #elif defined HAVE_LIBCRYPTO bignum_mod_exp(session->next_crypto->e, g, session->next_crypto->x, select_p(session->next_crypto->kex_type), ctx); +#elif defined HAVE_LIBMBEDCRYPTO + bignum_mod_exp(session->next_crypto->e, g, session->next_crypto->x, + select_p(session->next_crypto->kex_type), NULL); #endif #ifdef DEBUG_CRYPTO @@ -344,6 +362,9 @@ int ssh_dh_generate_f(ssh_session session) { #elif defined HAVE_LIBCRYPTO bignum_mod_exp(session->next_crypto->f, g, session->next_crypto->y, select_p(session->next_crypto->kex_type), ctx); +#elif defined HAVE_LIBMBEDCRYPTO + bignum_mod_exp(session->next_crypto->f, g, session->next_crypto->y, + select_p(session->next_crypto->kex_type), NULL); #endif #ifdef DEBUG_CRYPTO @@ -430,6 +451,14 @@ int ssh_dh_build_k(ssh_session session) { bignum_mod_exp(session->next_crypto->k, session->next_crypto->e, session->next_crypto->y, select_p(session->next_crypto->kex_type), ctx); } +#elif defined HAVE_LIBMBEDCRYPTO + if (session->client) { + bignum_mod_exp(session->next_crypto->k, session->next_crypto->f, + session->next_crypto->x, select_p(session->next_crypto->kex_type), NULL); + } else { + bignum_mod_exp(session->next_crypto->k, session->next_crypto->e, + session->next_crypto->y, select_p(session->next_crypto->kex_type), NULL); + } #endif #ifdef DEBUG_CRYPTO diff --git a/src/ecdh_mbedcrypto.c b/src/ecdh_mbedcrypto.c new file mode 100644 index 00000000..d4e7a774 --- /dev/null +++ b/src/ecdh_mbedcrypto.c @@ -0,0 +1,295 @@ +/* + * This file is part of the SSH Library + * + * Copyright (c) 2017 Sartura d.o.o. + * + * Author: Juraj Vijtiuk <juraj.vijtiuk@sartura.hr> + * + * The SSH Library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * The SSH Library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the SSH Library; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +#include "config.h" + +#include "libssh/session.h" +#include "libssh/ecdh.h" +#include "libssh/buffer.h" +#include "libssh/ssh2.h" +#include "libssh/dh.h" +#include "libssh/pki.h" +#include "libssh/bignum.h" +#include "libssh/libmbedcrypto.h" + +#include <mbedtls/ecdh.h> +#include <mbedtls/ecp.h> + +#ifdef HAVE_ECDH + +static mbedtls_ecp_group_id ecdh_kex_type_to_curve(enum ssh_key_exchange_e kex_type) { + if (kex_type == SSH_KEX_ECDH_SHA2_NISTP256) { + return MBEDTLS_ECP_DP_SECP256R1; + } else if (kex_type == SSH_KEX_ECDH_SHA2_NISTP384) { + return MBEDTLS_ECP_DP_SECP384R1; + } else if (kex_type == SSH_KEX_ECDH_SHA2_NISTP521) { + return MBEDTLS_ECP_DP_SECP521R1; + } + + return MBEDTLS_ECP_DP_NONE; +} +int ssh_client_ecdh_init(ssh_session session) +{ + ssh_string client_pubkey = NULL; + mbedtls_ecp_group grp; + int rc; + mbedtls_ecp_group_id curve; + + curve = ecdh_kex_type_to_curve(session->next_crypto->kex_type); + if (curve == MBEDTLS_ECP_DP_NONE) { + return SSH_ERROR; + } + + rc = ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_KEX_ECDH_INIT); + if (rc < 0) { + return SSH_ERROR; + } + + session->next_crypto->ecdh_privkey = malloc(sizeof(mbedtls_ecp_keypair)); + if (session->next_crypto->ecdh_privkey == NULL) { + return SSH_ERROR; + } + + mbedtls_ecp_keypair_init(session->next_crypto->ecdh_privkey); + mbedtls_ecp_group_init(&grp); + + rc = mbedtls_ecp_group_load(&grp, curve); + if (rc != 0) { + rc = SSH_ERROR; + goto out; + } + + rc = mbedtls_ecp_gen_keypair(&grp, &session->next_crypto->ecdh_privkey->d, + &session->next_crypto->ecdh_privkey->Q, mbedtls_ctr_drbg_random, + &ssh_mbedtls_ctr_drbg); + + if (rc != 0) { + rc = SSH_ERROR; + goto out; + } + + client_pubkey = make_ecpoint_string(&grp, + &session->next_crypto->ecdh_privkey->Q); + if (client_pubkey == NULL) { + rc = SSH_ERROR; + goto out; + } + + rc = ssh_buffer_add_ssh_string(session->out_buffer, client_pubkey); + if (rc < 0) { + rc = SSH_ERROR; + goto out; + } + + session->next_crypto->ecdh_client_pubkey = client_pubkey; + client_pubkey = NULL; + + rc = ssh_packet_send(session); + +out: + mbedtls_ecp_group_free(&grp); + ssh_string_free(client_pubkey); + + return rc; +} + +int ecdh_build_k(ssh_session session) +{ + mbedtls_ecp_group grp; + mbedtls_ecp_point pubkey; + int rc; + mbedtls_ecp_group_id curve; + + curve = ecdh_kex_type_to_curve(session->next_crypto->kex_type); + if (curve == MBEDTLS_ECP_DP_NONE) { + return SSH_ERROR; + } + + mbedtls_ecp_group_init(&grp); + mbedtls_ecp_point_init(&pubkey); + + rc = mbedtls_ecp_group_load(&grp, curve); + if (rc != 0) { + rc = SSH_ERROR; + goto out; + } + + if (session->server) { + rc = mbedtls_ecp_point_read_binary(&grp, &pubkey, + ssh_string_data(session->next_crypto->ecdh_client_pubkey), + ssh_string_len(session->next_crypto->ecdh_client_pubkey)); + } else { + rc = mbedtls_ecp_point_read_binary(&grp, &pubkey, + ssh_string_data(session->next_crypto->ecdh_server_pubkey), + ssh_string_len(session->next_crypto->ecdh_server_pubkey)); + } + + if (rc != 0) { + rc = SSH_ERROR; + goto out; + } + + session->next_crypto->k = malloc(sizeof(mbedtls_mpi)); + if (session->next_crypto->k == NULL) { + rc = SSH_ERROR; + goto out; + } + + mbedtls_mpi_init(session->next_crypto->k); + + rc = mbedtls_ecdh_compute_shared(&grp, session->next_crypto->k, &pubkey, + &session->next_crypto->ecdh_privkey->d, mbedtls_ctr_drbg_random, + &ssh_mbedtls_ctr_drbg); + if (rc != 0) { + rc = SSH_ERROR; + goto out; + } + +out: + mbedtls_ecp_keypair_free(session->next_crypto->ecdh_privkey); + SAFE_FREE(session->next_crypto->ecdh_privkey); + mbedtls_ecp_group_free(&grp); + mbedtls_ecp_point_free(&pubkey); + return rc; +} + +#ifdef WITH_SERVER +int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet) +{ + ssh_string q_c_string = NULL; + ssh_string q_s_string = NULL; + mbedtls_ecp_group grp; + ssh_key privkey = NULL; + ssh_string sig_blob = NULL; + int rc; + mbedtls_ecp_group_id curve; + + curve = ecdh_kex_type_to_curve(session->next_crypto->kex_type); + if (curve == MBEDTLS_ECP_DP_NONE) { + return SSH_ERROR; + } + + q_c_string = ssh_buffer_get_ssh_string(packet); + if (q_c_string == NULL) { + ssh_set_error(session, SSH_FATAL, "No Q_C ECC point in packet"); + return SSH_ERROR; + } + + session->next_crypto->ecdh_privkey = malloc(sizeof(mbedtls_ecp_keypair)); + if (session->next_crypto->ecdh_privkey == NULL) { + ssh_set_error_oom(session); + return SSH_ERROR; + } + + session->next_crypto->ecdh_client_pubkey = q_c_string; + + mbedtls_ecp_group_init(&grp); + mbedtls_ecp_keypair_init(session->next_crypto->ecdh_privkey); + + rc = mbedtls_ecp_group_load(&grp, curve); + if (rc != 0) { + rc = SSH_ERROR; + goto out; + } + + rc = mbedtls_ecp_gen_keypair(&grp, &session->next_crypto->ecdh_privkey->d, + &session->next_crypto->ecdh_privkey->Q, mbedtls_ctr_drbg_random, + &ssh_mbedtls_ctr_drbg); + if (rc != 0) { + rc = SSH_ERROR; + goto out; + } + + q_s_string = make_ecpoint_string(&grp, &session->next_crypto->ecdh_privkey->Q); + if (q_s_string == NULL) { + rc = SSH_ERROR; + goto out; + } + + session->next_crypto->ecdh_server_pubkey = q_s_string; + + /* build k and session_id */ + rc = ecdh_build_k(session); + if (rc != SSH_OK) { + ssh_set_error(session, SSH_FATAL, "Cannot build k number"); + goto out; + } + + /* privkey is not allocated */ + rc = ssh_get_key_params(session, &privkey); + if (rc == SSH_ERROR) { + rc = SSH_ERROR; + goto out; + } + + rc = ssh_make_sessionid(session); + if (rc != SSH_OK) { + ssh_set_error(session, SSH_FATAL, "Could not create a session id"); + rc = SSH_ERROR; + goto out; + } + + sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey); + if (sig_blob == NULL) { + ssh_set_error(session, SSH_FATAL, "Could not sign the session id"); + rc = SSH_ERROR; + goto out; + } + + rc = ssh_buffer_pack(session->out_buffer, "bSSS", + SSH2_MSG_KEXDH_REPLY, session->next_crypto->server_pubkey, + q_s_string, + sig_blob); + + ssh_string_free(sig_blob); + + if (rc != SSH_OK) { + ssh_set_error_oom(session); + rc = SSH_ERROR; + goto out; + } + + SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEXDH_REPLY sent"); + rc = ssh_packet_send(session); + if (rc != SSH_OK) { + rc = SSH_ERROR; + goto out; + } + + rc = ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS); + if (rc < 0) { + rc = SSH_ERROR; + goto out; + } + + session->dh_handshake_state = DH_STATE_NEWKEYS_SENT; + rc = ssh_packet_send(session); + SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent"); + +out: + mbedtls_ecp_group_free(&grp); + return rc; +} + +#endif /* WITH_SERVER */ +#endif @@ -43,6 +43,12 @@ # define DES "3des-cbc" # define DES_SUPPORTED "3des-cbc,des-cbc-ssh1" +#elif defined HAVE_LIBMBEDCRYPTO +# define BLOWFISH "blowfish-cbc," +# define AES "aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc,aes192-cbc,aes128-cbc," +# define DES "3des-cbc" +# define DES_SUPPORTED "3des-cbc,des-cbc-ssh1" + #elif defined(HAVE_LIBCRYPTO) # ifdef HAVE_OPENSSL_BLOWFISH_H @@ -81,7 +87,11 @@ #define ECDH "ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521," #define HOSTKEYS "ssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-rsa,ssh-dss" #else +#ifdef HAVE_DSA #define HOSTKEYS "ssh-ed25519,ssh-rsa,ssh-dss" +#else +#define HOSTKEYS "ssh-ed25519,ssh-rsa" +#endif #define ECDH "" #endif @@ -560,7 +570,9 @@ static char *ssh_client_select_hostkeys(ssh_session session){ "ecdsa-sha2-nistp384", "ecdsa-sha2-nistp256", "ssh-rsa", +#ifdef HAVE_DSA "ssh-dss", +#endif "ssh-rsa1", NULL }; diff --git a/src/known_hosts.c b/src/known_hosts.c index a6bb32f1..2f0584d8 100644 --- a/src/known_hosts.c +++ b/src/known_hosts.c @@ -220,7 +220,11 @@ static int check_public_key(ssh_session session, char **tokens) { for (i = 2; i < 4; i++) { /* e, then n */ tmpbn = NULL; +#ifdef HAVE_LIBMBEDCRYPTO + bignum_dec2bn(tokens[i], tmpbn); +#else bignum_dec2bn(tokens[i], &tmpbn); +#endif if (tmpbn == NULL) { ssh_buffer_free(pubkey_buffer); return -1; @@ -242,6 +246,8 @@ static int check_public_key(ssh_session session, char **tokens) { bignum_bn2bin(tmpbn, len, ssh_string_data(tmpstring)); #elif defined HAVE_LIBCRYPTO bignum_bn2bin(tmpbn, ssh_string_data(tmpstring)); +#elif defined HAVE_LIBMBEDCRYPTO + bignum_bn2bin(tmpbn, ssh_string_data(tmpstring)); #endif bignum_free(tmpbn); if (ssh_buffer_add_ssh_string(pubkey_buffer, tmpstring) < 0) { diff --git a/src/legacy.c b/src/legacy.c index 3f09992c..139f81b5 100644 --- a/src/legacy.c +++ b/src/legacy.c @@ -362,6 +362,9 @@ void publickey_free(ssh_public_key key) { gcry_sexp_release(key->rsa_pub); #elif defined HAVE_LIBCRYPTO RSA_free(key->rsa_pub); +#elif defined HAVE_LIBMBEDCRYPTO + mbedtls_pk_free(key->rsa_pub); + SAFE_FREE(key->rsa_pub); #endif break; default: @@ -463,6 +466,9 @@ void privatekey_free(ssh_private_key prv) { #elif defined HAVE_LIBCRYPTO DSA_free(prv->dsa_priv); RSA_free(prv->rsa_priv); +#elif defined HAVE_LIBMBEDCRYPTO + mbedtls_pk_free(prv->rsa_priv); + SAFE_FREE(prv->rsa_priv); #endif memset(prv, 0, sizeof(struct ssh_private_key_struct)); SAFE_FREE(prv); diff --git a/src/libmbedcrypto.c b/src/libmbedcrypto.c new file mode 100644 index 00000000..6854bd98 --- /dev/null +++ b/src/libmbedcrypto.c @@ -0,0 +1,1122 @@ +/* + * This file is part of the SSH Library + * + * Copyright (c) 2017 Sartura d.o.o. + * + * Author: Juraj Vijtiuk <juraj.vijtiuk@sartura.hr> + * + * The SSH Library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * The SSH Library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the SSH Library; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +#include "config.h" + +#include "libssh/wrapper.h" +#include "libssh/crypto.h" +#include "libssh/priv.h" + +#ifdef HAVE_LIBMBEDCRYPTO +#include <mbedtls/md.h> + +struct ssh_mac_ctx_struct { + enum ssh_mac_e mac_type; + mbedtls_md_context_t ctx; +}; + +void ssh_reseed(void) +{ + mbedtls_ctr_drbg_reseed(&ssh_mbedtls_ctr_drbg, NULL, 0); +} + +SHACTX sha1_init(void) +{ + SHACTX ctx = NULL; + int rc; + const mbedtls_md_info_t *md_info = + mbedtls_md_info_from_type(MBEDTLS_MD_SHA1); + + if (md_info == NULL) { + return NULL; + } + + ctx = malloc(sizeof(mbedtls_md_context_t)); + if (ctx == NULL) { + return NULL; + } + + mbedtls_md_init(ctx); + + rc = mbedtls_md_setup(ctx, md_info, 0); + if (rc != 0) { + SAFE_FREE(ctx); + return NULL; + } + + rc = mbedtls_md_starts(ctx); + if (rc != 0) { + SAFE_FREE(ctx); + return NULL; + } + + return ctx; +} + +void sha1_update(SHACTX c, const void *data, unsigned long len) +{ + mbedtls_md_update(c, data, len); +} + +void sha1_final(unsigned char *md, SHACTX c) +{ + mbedtls_md_finish(c, md); + mbedtls_md_free(c); + SAFE_FREE(c); +} + +void sha1(unsigned char *digest, int len, unsigned char *hash) +{ + const mbedtls_md_info_t *md_info = + mbedtls_md_info_from_type(MBEDTLS_MD_SHA1); + if (md_info != NULL) { + mbedtls_md(md_info, digest, len, hash); + } +} + +static mbedtls_md_type_t nid_to_md_algo(int nid) +{ + switch (nid) { + case NID_mbedtls_nistp256: + return MBEDTLS_MD_SHA256; + case NID_mbedtls_nistp384: + return MBEDTLS_MD_SHA384; + case NID_mbedtls_nistp521: + return MBEDTLS_MD_SHA512; + } + return MBEDTLS_MD_NONE; +} + +void evp(int nid, unsigned char *digest, int len, + unsigned char *hash, unsigned int *hlen) +{ + mbedtls_md_type_t algo = nid_to_md_algo(nid); + const mbedtls_md_info_t *md_info = + mbedtls_md_info_from_type(algo); + + + if (md_info != NULL) { + *hlen = mbedtls_md_get_size(md_info); + mbedtls_md(md_info, digest, len, hash); + } +} + +EVPCTX evp_init(int nid) +{ + EVPCTX ctx = NULL; + int rc; + mbedtls_md_type_t algo = nid_to_md_algo(nid); + const mbedtls_md_info_t *md_info = + mbedtls_md_info_from_type(algo); + + if (md_info == NULL) { + return NULL; + } + + ctx = malloc(sizeof(mbedtls_md_context_t)); + if (ctx == NULL) { + return NULL; + } + + mbedtls_md_init(ctx); + + rc = mbedtls_md_setup(ctx, md_info, 0); + if (rc != 0) { + SAFE_FREE(ctx); + return NULL; + } + + rc = mbedtls_md_starts(ctx); + if (rc != 0) { + SAFE_FREE(ctx); + return NULL; + } + + return ctx; +} + +void evp_update(EVPCTX ctx, const void *data, unsigned long len) +{ + mbedtls_md_update(ctx, data, len); +} + +void evp_final(EVPCTX ctx, unsigned char *md, unsigned int *mdlen) +{ + *mdlen = mbedtls_md_get_size(ctx->md_info); + mbedtls_md_hmac_finish(ctx, md); + mbedtls_md_free(ctx); + SAFE_FREE(ctx); +} + +SHA256CTX sha256_init(void) +{ + SHA256CTX ctx = NULL; + int rc; + const mbedtls_md_info_t *md_info = + mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); + + if (md_info == NULL) { + return NULL; + } + + ctx = malloc(sizeof(mbedtls_md_context_t)); + if(ctx == NULL) { + return NULL; + } + + mbedtls_md_init(ctx); + + rc = mbedtls_md_setup(ctx, md_info, 0); + if (rc != 0) { + SAFE_FREE(ctx); + return NULL; + } + + rc = mbedtls_md_starts(ctx); + if (rc != 0) { + SAFE_FREE(ctx); + return NULL; + } + + return ctx; +} + +void sha256_update(SHA256CTX c, const void *data, unsigned long len) +{ + mbedtls_md_update(c, data, len); +} + +void sha256_final(unsigned char *md, SHA256CTX c) +{ + mbedtls_md_finish(c, md); + mbedtls_md_free(c); + SAFE_FREE(c); +} + +void sha256(unsigned char *digest, int len, unsigned char *hash) +{ + const mbedtls_md_info_t *md_info = + mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); + if (md_info != NULL) { + mbedtls_md(md_info, digest, len, hash); + } +} + +SHA384CTX sha384_init(void) +{ + SHA384CTX ctx = NULL; + int rc; + const mbedtls_md_info_t *md_info = + mbedtls_md_info_from_type(MBEDTLS_MD_SHA384); + + if (md_info == NULL) { + return NULL; + } + + ctx = malloc(sizeof(mbedtls_md_context_t)); + if (ctx == NULL) { + return NULL; + } + + mbedtls_md_init(ctx); + + rc = mbedtls_md_setup(ctx, md_info, 0); + if (rc != 0) { + SAFE_FREE(ctx); + return NULL; + } + + rc = mbedtls_md_starts(ctx); + if (rc != 0) { + SAFE_FREE(ctx); + return NULL; + } + + return ctx; +} + +void sha384_update(SHA384CTX c, const void *data, unsigned long len) +{ + mbedtls_md_update(c, data, len); +} + +void sha384_final(unsigned char *md, SHA384CTX c) +{ + mbedtls_md_finish(c, md); + mbedtls_md_free(c); + SAFE_FREE(c); +} + +void sha384(unsigned char *digest, int len, unsigned char *hash) +{ + const mbedtls_md_info_t *md_info = + mbedtls_md_info_from_type(MBEDTLS_MD_SHA384); + if (md_info != NULL) { + mbedtls_md(md_info, digest, len, hash); + } +} + +SHA512CTX sha512_init(void) +{ + SHA512CTX ctx = NULL; + int rc; + const mbedtls_md_info_t *md_info = + mbedtls_md_info_from_type(MBEDTLS_MD_SHA512); + if (md_info == NULL) { + return NULL; + } + + ctx = malloc(sizeof(mbedtls_md_context_t)); + if (ctx == NULL) { + return NULL; + } + + mbedtls_md_init(ctx); + + rc = mbedtls_md_setup(ctx, md_info, 0); + if (rc != 0) { + SAFE_FREE(ctx); + return NULL; + } + + rc = mbedtls_md_starts(ctx); + if (rc != 0) { + SAFE_FREE(ctx); + return NULL; + } + + return ctx; +} + +void sha512_update(SHA512CTX c, const void *data, unsigned long len) +{ + mbedtls_md_update(c, data, len); +} + +void sha512_final(unsigned char *md, SHA512CTX c) +{ + mbedtls_md_finish(c, md); + mbedtls_md_free(c); + SAFE_FREE(c); +} + +void sha512(unsigned char *digest, int len, unsigned char *hash) +{ + const mbedtls_md_info_t *md_info = + mbedtls_md_info_from_type(MBEDTLS_MD_SHA512); + if (md_info != NULL) { + mbedtls_md(md_info, digest, len, hash); + } +} + +MD5CTX md5_init(void) +{ + MD5CTX ctx = NULL; + int rc; + const mbedtls_md_info_t *md_info = + mbedtls_md_info_from_type(MBEDTLS_MD_MD5); + if (md_info == NULL) { + return NULL; + } + + ctx = malloc(sizeof(mbedtls_md_context_t)); + if (ctx == NULL) { + return NULL; + } + + mbedtls_md_init(ctx); + + rc = mbedtls_md_setup(ctx, md_info, 0); + if (rc != 0) { + SAFE_FREE(ctx); + return NULL; + } + + rc = mbedtls_md_starts(ctx); + if (rc != 0) { + SAFE_FREE(ctx); + return NULL; + } + + return ctx; +} + + +void md5_update(MD5CTX c, const void *data, unsigned long len) { + mbedtls_md_update(c, data, len); +} + +void md5_final(unsigned char *md, MD5CTX c) +{ + mbedtls_md_finish(c, md); + mbedtls_md_free(c); + SAFE_FREE(c); +} + +ssh_mac_ctx ssh_mac_ctx_init(enum ssh_mac_e type) +{ + ssh_mac_ctx ctx = malloc(sizeof (struct ssh_mac_ctx_struct)); + const mbedtls_md_info_t *md_info; + int rc; + if (ctx == NULL) { + return NULL; + } + + ctx->mac_type=type; + switch(type) { + case SSH_MAC_SHA1: + md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1); + break; + case SSH_MAC_SHA256: + md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); + break; + case SSH_MAC_SHA384: + md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA384); + break; + case SSH_MAC_SHA512: + md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512); + break; + default: + goto error; + } + + if (md_info == NULL) { + goto error; + } + + mbedtls_md_init(&ctx->ctx); + + rc = mbedtls_md_setup(&ctx->ctx, md_info, 0); + if (rc != 0) { + goto error; + } + + rc = mbedtls_md_starts(&ctx->ctx); + if (rc != 0) { + goto error; + } + + return ctx; + +error: + SAFE_FREE(ctx); + return NULL; +} + +void ssh_mac_update(ssh_mac_ctx ctx, const void *data, unsigned long len) +{ + mbedtls_md_update(&ctx->ctx, data, len); +} + +void ssh_mac_final(unsigned char *md, ssh_mac_ctx ctx) +{ + mbedtls_md_finish(&ctx->ctx, md); + mbedtls_md_free(&ctx->ctx); + SAFE_FREE(ctx); +} + +HMACCTX hmac_init(const void *key, int len, enum ssh_hmac_e type) +{ + HMACCTX ctx = NULL; + const mbedtls_md_info_t *md_info = NULL; + int rc; + + ctx = malloc(sizeof(mbedtls_md_context_t)); + if (ctx == NULL) { + return NULL; + } + + switch (type) { + case SSH_HMAC_SHA1: + md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1); + break; + case SSH_HMAC_SHA256: + md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); + break; + case SSH_HMAC_SHA384: + md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA384); + break; + case SSH_HMAC_SHA512: + md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512); + break; + default: + goto error; + } + + mbedtls_md_init(ctx); + + if (md_info == NULL) { + goto error; + } + + rc = mbedtls_md_setup(ctx, md_info, 1); + if (rc != 0) { + goto error; + } + + rc = mbedtls_md_hmac_starts(ctx, key, len); + if (rc != 0) { + goto error; + } + + return ctx; + +error: + mbedtls_md_free(ctx); + SAFE_FREE(ctx); + return NULL; +} + +void hmac_update(HMACCTX c, const void *data, unsigned long len) +{ + mbedtls_md_hmac_update(c, data, len); +} + +void hmac_final(HMACCTX c, unsigned char *hashmacbuf, unsigned int *len) +{ + *len = mbedtls_md_get_size(c->md_info); + mbedtls_md_hmac_finish(c, hashmacbuf); + mbedtls_md_free(c); + SAFE_FREE(c); +} + +static int cipher_set_encrypt_key(struct ssh_cipher_struct *cipher, void *key, + void *IV) +{ + + const mbedtls_cipher_info_t *cipher_info = NULL; + int rc; + + mbedtls_cipher_init(&cipher->encrypt_ctx); + cipher_info = mbedtls_cipher_info_from_type(cipher->type); + + rc = mbedtls_cipher_setup(&cipher->encrypt_ctx, cipher_info); + if (rc != 0) { + SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setup failed"); + goto error; + } + + rc = mbedtls_cipher_setkey(&cipher->encrypt_ctx, key, + cipher_info->key_bitlen, + MBEDTLS_ENCRYPT); + if (rc != 0) { + SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setkey failed"); + goto error; + } + + rc = mbedtls_cipher_set_iv(&cipher->encrypt_ctx, IV, cipher_info->iv_size); + + if (rc != 0) { + SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_set_iv failed"); + goto error; + } + + rc = mbedtls_cipher_reset(&cipher->encrypt_ctx); + + if (rc != 0) { + SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_reset failed"); + goto error; + } + + return SSH_OK; +error: + mbedtls_cipher_free(&cipher->encrypt_ctx); + return SSH_ERROR; +} + +static int cipher_set_encrypt_key_cbc(struct ssh_cipher_struct *cipher, void *key, + void *IV) +{ + + const mbedtls_cipher_info_t *cipher_info = NULL; + int rc; + + mbedtls_cipher_init(&cipher->encrypt_ctx); + cipher_info = mbedtls_cipher_info_from_type(cipher->type); + + rc = mbedtls_cipher_setup(&cipher->encrypt_ctx, cipher_info); + if (rc != 0) { + SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setup failed"); + goto error; + } + + rc = mbedtls_cipher_setkey(&cipher->encrypt_ctx, key, + cipher_info->key_bitlen, + MBEDTLS_ENCRYPT); + if (rc != 0) { + SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setkey failed"); + goto error; + } + + rc = mbedtls_cipher_set_iv(&cipher->encrypt_ctx, IV, cipher_info->iv_size); + + if (rc != 0) { + SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_set_iv failed"); + goto error; + } + + /* libssh only encypts and decrypts packets that are multiples of a block + * size, and no padding is used */ + rc = mbedtls_cipher_set_padding_mode(&cipher->encrypt_ctx, + MBEDTLS_PADDING_NONE); + + if (rc != 0) { + SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_set_padding_mode failed"); + goto error; + } + + rc = mbedtls_cipher_reset(&cipher->encrypt_ctx); + + if (rc != 0) { + SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_reset failed"); + goto error; + } + + return SSH_OK; +error: + mbedtls_cipher_free(&cipher->encrypt_ctx); + return SSH_ERROR; +} + +static int cipher_set_decrypt_key(struct ssh_cipher_struct *cipher, void *key, + void *IV) +{ + const mbedtls_cipher_info_t *cipher_info = NULL; + int rc; + + mbedtls_cipher_init(&cipher->decrypt_ctx); + cipher_info = mbedtls_cipher_info_from_type(cipher->type); + + rc = mbedtls_cipher_setup(&cipher->decrypt_ctx, cipher_info); + if (rc != 0) { + SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setkey failed"); + goto error; + } + + rc = mbedtls_cipher_setkey(&cipher->decrypt_ctx, key, + cipher_info->key_bitlen, + MBEDTLS_DECRYPT); + if (rc != 0) { + SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setkey failed"); + goto error; + } + + rc = mbedtls_cipher_set_iv(&cipher->decrypt_ctx, IV, cipher_info->iv_size); + if (rc != 0) { + SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_set_iv failed"); + goto error; + } + + mbedtls_cipher_reset(&cipher->decrypt_ctx); + + if (rc != 0) { + SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_reset failed"); + goto error; + } + + return SSH_OK; +error: + mbedtls_cipher_free(&cipher->decrypt_ctx); + return SSH_ERROR; +} + +static int cipher_set_decrypt_key_cbc(struct ssh_cipher_struct *cipher, void *key, + void *IV) +{ + const mbedtls_cipher_info_t *cipher_info; + int rc; + + mbedtls_cipher_init(&cipher->decrypt_ctx); + cipher_info = mbedtls_cipher_info_from_type(cipher->type); + + rc = mbedtls_cipher_setup(&cipher->decrypt_ctx, cipher_info); + if (rc != 0) { + SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setkey failed"); + goto error; + } + + rc = mbedtls_cipher_setkey(&cipher->decrypt_ctx, key, + cipher_info->key_bitlen, + MBEDTLS_DECRYPT); + if (rc != 0) { + SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setkey failed"); + goto error; + } + + rc = mbedtls_cipher_set_iv(&cipher->decrypt_ctx, IV, cipher_info->iv_size); + if (rc != 0) { + SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_set_iv failed"); + goto error; + } + + rc = mbedtls_cipher_set_padding_mode(&cipher->decrypt_ctx, + MBEDTLS_PADDING_NONE); + + if (rc != 0) { + SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_set_padding_mode failed"); + goto error; + } + + mbedtls_cipher_reset(&cipher->decrypt_ctx); + + if (rc != 0) { + SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_reset failed"); + goto error; + } + + return SSH_OK; +error: + mbedtls_cipher_free(&cipher->decrypt_ctx); + return SSH_ERROR; +} + +static void cipher_encrypt(struct ssh_cipher_struct *cipher, void *in, void *out, + unsigned long len) +{ + size_t outlen = 0; + size_t total_len = 0; + int rc = 0; + rc = mbedtls_cipher_update(&cipher->encrypt_ctx, in, len, out, &outlen); + if (rc != 0) { + SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_update failed during encryption"); + return; + } + + total_len += outlen; + + if (total_len == len) { + return; + } + + rc = mbedtls_cipher_finish(&cipher->encrypt_ctx, (unsigned char *) out + outlen, + &outlen); + + total_len += outlen; + + if (rc != 0) { + SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_finish failed during encryption"); + return; + } + + if (total_len != len) { + SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_update: output size %zu for %zu", + outlen, len); + return; + } + +} + +static void cipher_encrypt_cbc(struct ssh_cipher_struct *cipher, void *in, void *out, + unsigned long len) +{ + size_t outlen = 0; + int rc = 0; + rc = mbedtls_cipher_update(&cipher->encrypt_ctx, in, len, out, &outlen); + if (rc != 0) { + SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_update failed during encryption"); + return; + } + + if (outlen != len) { + SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_update: output size %zu for %zu", + outlen, len); + return; + } + +} + +static void cipher_decrypt(struct ssh_cipher_struct *cipher, void *in, void *out, + unsigned long len) +{ + size_t outlen = 0; + int rc = 0; + size_t total_len = 0; + + rc = mbedtls_cipher_update(&cipher->decrypt_ctx, in, len, out, &outlen); + if (rc != 0) { + SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_update failed during decryption"); + return; + } + + total_len += outlen; + + if (total_len == len) { + return; + } + + rc = mbedtls_cipher_finish(&cipher->decrypt_ctx, (unsigned char *) out + + outlen, &outlen); + + if (rc != 0) { + SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_reset failed during decryption"); + return; + } + + total_len += outlen; + + if (total_len != len) { + SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_update: output size %zu for %zu", + outlen, len); + return; + } + +} + +static void cipher_decrypt_cbc(struct ssh_cipher_struct *cipher, void *in, void *out, + unsigned long len) +{ + size_t outlen = 0; + int rc = 0; + rc = mbedtls_cipher_update(&cipher->decrypt_ctx, in, len, out, &outlen); + if (rc != 0) { + SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_update failed during decryption"); + return; + } + + /* MbedTLS caches the last block when decrypting with cbc. + * By calling finish the block is flushed to out, however the unprocessed + * data counter is not reset. + * Calling mbedtls_cipher_reset resets the unprocessed data counter. + */ + if (outlen == 0) { + rc = mbedtls_cipher_finish(&cipher->decrypt_ctx, out, &outlen); + } else if (outlen == len) { + return; + } else { + rc = mbedtls_cipher_finish(&cipher->decrypt_ctx, (unsigned char *) out + + outlen , &outlen); + } + + if (rc != 0) { + SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_finish failed during decryption"); + return; + } + + rc = mbedtls_cipher_reset(&cipher->decrypt_ctx); + + if (rc != 0) { + SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_reset failed during decryption"); + return; + } + + if (outlen != len) { + SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_update: output size %zu for %zu", + outlen, len); + return; + } + +} + +static void cipher_cleanup(struct ssh_cipher_struct *cipher) +{ + mbedtls_cipher_free(&cipher->encrypt_ctx); + mbedtls_cipher_free(&cipher->decrypt_ctx); +} + +static int des3_set_encrypt_key(struct ssh_cipher_struct *cipher, void *key, + void *IV) +{ + const mbedtls_cipher_info_t *cipher_info = NULL; + unsigned char *des3_key = NULL; + size_t des_key_size = 0; + int rc; + + mbedtls_cipher_init(&cipher->encrypt_ctx); + cipher_info = mbedtls_cipher_info_from_type(cipher->type); + + rc = mbedtls_cipher_setup(&cipher->encrypt_ctx, cipher_info); + if (rc != 0) { + SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setup failed"); + goto error; + } + + des3_key = malloc(cipher_info->key_bitlen / 8); + if (des3_key == NULL) { + SSH_LOG(SSH_LOG_WARNING, "error allocating memory for key"); + goto error; + } + + des_key_size = cipher_info->key_bitlen / (8 * 3); + memcpy(des3_key, key, des_key_size); + memcpy(des3_key + des_key_size, (unsigned char * )key + des_key_size, + des_key_size); + memcpy(des3_key + 2 * des_key_size, + (unsigned char *) key + 2 * des_key_size, des_key_size); + + rc = mbedtls_cipher_setkey(&cipher->encrypt_ctx, des3_key, + cipher_info->key_bitlen, + MBEDTLS_ENCRYPT); + if (rc != 0) { + SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setkey failed"); + goto error; + } + + rc = mbedtls_cipher_set_iv(&cipher->encrypt_ctx, IV, cipher_info->iv_size); + + if (rc != 0) { + SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_set_iv failed"); + goto error; + } + + rc = mbedtls_cipher_reset(&cipher->encrypt_ctx); + + if (rc != 0) { + SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_reset failed"); + goto error; + } + + SAFE_FREE(des3_key); + return SSH_OK; +error: + mbedtls_cipher_free(&cipher->encrypt_ctx); + SAFE_FREE(des3_key); + return SSH_ERROR; +} + +static int des3_set_decrypt_key(struct ssh_cipher_struct *cipher, void *key, + void *IV) +{ + const mbedtls_cipher_info_t *cipher_info = NULL; + unsigned char *des3_key = NULL; + size_t des_key_size = 0; + int rc; + + mbedtls_cipher_init(&cipher->decrypt_ctx); + cipher_info = mbedtls_cipher_info_from_type(cipher->type); + + rc = mbedtls_cipher_setup(&cipher->decrypt_ctx, cipher_info); + if (rc != 0) { + SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setup failed"); + goto error; + } + + des3_key = malloc(cipher_info->key_bitlen / 8); + if (des3_key == NULL) { + SSH_LOG(SSH_LOG_WARNING, "error allocating memory for key"); + goto error; + } + + des_key_size = cipher_info->key_bitlen / (8 * 3); + memcpy(des3_key, key, des_key_size); + memcpy(des3_key + des_key_size, (unsigned char *) key + des_key_size, + des_key_size); + memcpy(des3_key + 2 * des_key_size, + (unsigned char *) key + 2 * des_key_size, + des_key_size); + + rc = mbedtls_cipher_setkey(&cipher->decrypt_ctx, des3_key, + cipher_info->key_bitlen, + MBEDTLS_DECRYPT); + if (rc != 0) { + SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setkey failed"); + goto error; + } + + rc = mbedtls_cipher_set_iv(&cipher->decrypt_ctx, IV, cipher_info->iv_size); + + if (rc != 0) { + SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_set_iv failed"); + goto error; + } + + rc = mbedtls_cipher_reset(&cipher->decrypt_ctx); + + if (rc != 0) { + SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_reset failed"); + goto error; + } + + SAFE_FREE(des3_key); + return SSH_OK; +error: + mbedtls_cipher_free(&cipher->decrypt_ctx); + if (des3_key != NULL) { + SAFE_FREE(des3_key); + } + return SSH_ERROR; +} + +static struct ssh_cipher_struct ssh_ciphertab[] = { + { + .name = "blowfish-cbc", + .blocksize = 8, + .keysize = 128, + .type = MBEDTLS_CIPHER_BLOWFISH_CBC, + .set_encrypt_key = cipher_set_encrypt_key_cbc, + .set_decrypt_key = cipher_set_decrypt_key_cbc, + .encrypt = cipher_encrypt_cbc, + .decrypt = cipher_decrypt_cbc, + .cleanup = cipher_cleanup + }, + { + .name = "aes128-ctr", + .blocksize = 16, + .keysize = 128, + .type = MBEDTLS_CIPHER_AES_128_CTR, + .set_encrypt_key = cipher_set_encrypt_key, + .set_decrypt_key = cipher_set_decrypt_key, + .encrypt = cipher_encrypt, + .decrypt = cipher_decrypt, + .cleanup = cipher_cleanup + }, + { + .name = "aes192-ctr", + .blocksize = 16, + .keysize = 192, + .type = MBEDTLS_CIPHER_AES_192_CTR, + .set_encrypt_key = cipher_set_encrypt_key, + .set_decrypt_key = cipher_set_decrypt_key, + .encrypt = cipher_encrypt, + .decrypt = cipher_decrypt, + .cleanup = cipher_cleanup + }, + { + .name = "aes256-ctr", + .blocksize = 16, + .keysize = 256, + .type = MBEDTLS_CIPHER_AES_256_CTR, + .set_encrypt_key = cipher_set_encrypt_key, + .set_decrypt_key = cipher_set_decrypt_key, + .encrypt = cipher_encrypt, + .decrypt = cipher_decrypt, + .cleanup = cipher_cleanup + }, + { + .name = "aes128-cbc", + .blocksize = 16, + .keysize = 128, + .type = MBEDTLS_CIPHER_AES_128_CBC, + .set_encrypt_key = cipher_set_encrypt_key_cbc, + .set_decrypt_key = cipher_set_decrypt_key_cbc, + .encrypt = cipher_encrypt_cbc, + .decrypt = cipher_decrypt_cbc, + .cleanup = cipher_cleanup + }, + { + .name = "aes192-cbc", + .blocksize = 16, + .keysize = 192, + .type = MBEDTLS_CIPHER_AES_192_CBC, + .set_encrypt_key = cipher_set_encrypt_key_cbc, + .set_decrypt_key = cipher_set_decrypt_key_cbc, + .encrypt = cipher_encrypt_cbc, + .decrypt = cipher_decrypt_cbc, + .cleanup = cipher_cleanup + }, + { + .name = "aes256-cbc", + .blocksize = 16, + .keysize = 256, + .type = MBEDTLS_CIPHER_AES_256_CBC, + .set_encrypt_key = cipher_set_encrypt_key_cbc, + .set_decrypt_key = cipher_set_decrypt_key_cbc, + .encrypt = cipher_encrypt_cbc, + .decrypt = cipher_decrypt_cbc, + .cleanup = cipher_cleanup + }, + { + .name = "3des-cbc", + .blocksize = 8, + .keysize = 192, + .type = MBEDTLS_CIPHER_DES_EDE3_CBC, + .set_encrypt_key = cipher_set_encrypt_key_cbc, + .set_decrypt_key = cipher_set_decrypt_key_cbc, + .encrypt = cipher_encrypt_cbc, + .decrypt = cipher_decrypt_cbc, + .cleanup = cipher_cleanup + }, + { + .name = "3des-cbc-ssh1", + .blocksize = 8, + .keysize = 192, + .type = MBEDTLS_CIPHER_DES_CBC, + .set_encrypt_key = des3_set_encrypt_key, + .set_decrypt_key = des3_set_decrypt_key, + .encrypt = cipher_encrypt_cbc, + .decrypt = cipher_decrypt_cbc, + .cleanup = cipher_cleanup + }, + { + .name = "des-cbc-ssh1", + .blocksize = 8, + .keysize = 64, + .type = MBEDTLS_CIPHER_DES_CBC, + .set_encrypt_key = cipher_set_encrypt_key_cbc, + .set_decrypt_key = cipher_set_decrypt_key_cbc, + .encrypt = cipher_encrypt_cbc, + .decrypt = cipher_decrypt_cbc, + }, + { + .name = NULL, + .blocksize = 0, + .keysize = 0, + .set_encrypt_key = NULL, + .set_decrypt_key = NULL, + .encrypt = NULL, + .decrypt = NULL, + .cleanup = NULL + } +}; + +struct ssh_cipher_struct *ssh_get_ciphertab(void) +{ + return ssh_ciphertab; +} + +void ssh_mbedtls_init(void) +{ + int rc; + + mbedtls_entropy_init(&ssh_mbedtls_entropy); + mbedtls_ctr_drbg_init(&ssh_mbedtls_ctr_drbg); + + rc = mbedtls_ctr_drbg_seed(&ssh_mbedtls_ctr_drbg, mbedtls_entropy_func, + &ssh_mbedtls_entropy, NULL, 0); + if (rc != 0) { + mbedtls_ctr_drbg_free(&ssh_mbedtls_ctr_drbg); + } +} + +int ssh_mbedtls_random(void *where, int len, int strong) +{ + int rc = 0; + if (strong) { + mbedtls_ctr_drbg_set_prediction_resistance(&ssh_mbedtls_ctr_drbg, + MBEDTLS_CTR_DRBG_PR_ON); + rc = mbedtls_ctr_drbg_random(&ssh_mbedtls_ctr_drbg, where, len); + mbedtls_ctr_drbg_set_prediction_resistance(&ssh_mbedtls_ctr_drbg, + MBEDTLS_CTR_DRBG_PR_OFF); + } else { + rc = mbedtls_ctr_drbg_random(&ssh_mbedtls_ctr_drbg, where, len); + } + + return !rc; +} + +void ssh_mbedtls_cleanup(void) +{ + mbedtls_ctr_drbg_free(&ssh_mbedtls_ctr_drbg); + mbedtls_entropy_free(&ssh_mbedtls_entropy); +} + +#endif /* HAVE_LIBMBEDCRYPTO */ diff --git a/src/mbedcrypto_missing.c b/src/mbedcrypto_missing.c new file mode 100644 index 00000000..44ac7ddc --- /dev/null +++ b/src/mbedcrypto_missing.c @@ -0,0 +1,128 @@ +/* + * This file is part of the SSH Library + * + * Copyright (c) 2017 Sartura d.o.o. + * + * Author: Juraj Vijtiuk <juraj.vijtiuk@sartura.hr> + * + * The SSH Library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * The SSH Library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the SSH Library; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +#include "config.h" + +#include "libssh/priv.h" +#include "libssh/libmbedcrypto.h" + +#ifdef HAVE_LIBMBEDCRYPTO +bignum ssh_mbedcry_bn_new(void) +{ + bignum bn; + + bn = malloc(sizeof(mbedtls_mpi)); + if (bn) { + mbedtls_mpi_init(bn); + } + + return bn; +} + +void ssh_mbedcry_bn_free(bignum bn) +{ + mbedtls_mpi_free(bn); + SAFE_FREE(bn); +} + +char *ssh_mbedcry_bn2num(bignum num, int radix) +{ + char *buf = NULL; + size_t olen; + int rc; + + rc = mbedtls_mpi_write_string(num, radix, buf, 0, &olen); + if (rc != 0) { + return NULL; + } + + buf = malloc(olen); + if (buf == NULL) { + return NULL; + } + + rc = mbedtls_mpi_write_string(num, radix, buf, olen, &olen); + if (rc != 0) { + SAFE_FREE(buf); + return NULL; + } + + return buf; +} + +int ssh_mbedcry_rand(bignum rnd, int bits, int top, int bottom) +{ + size_t len; + int rc; + int i; + + if (bits <= 0) { + return 0; + } + + len = bits / 8 + 1; + rc = mbedtls_mpi_fill_random(rnd, len, mbedtls_ctr_drbg_random, + &ssh_mbedtls_ctr_drbg); + if (rc != 0) { + return 0; + } + + for (i = len * 8 - 1; i >= bits; i--) { + rc = mbedtls_mpi_set_bit(rnd, i, 0); + if (rc != 0) { + return 0; + } + } + + if (top == 0) { + rc = mbedtls_mpi_set_bit(rnd, bits - 1, 0); + } + + if (top == 1) { + if (bits < 2) { + return 0; + } + + rc = mbedtls_mpi_set_bit(rnd, bits - 2, 0); + if (rc != 0) { + return 0; + } + } + + if (bottom) { + rc = mbedtls_mpi_set_bit(rnd, 0, 1); + if (rc != 0) { + return 0; + } + } + + return 1; +} + +int ssh_mbedcry_is_bit_set(bignum num, size_t pos) +{ + int bit; + bit = mbedtls_mpi_get_bit(num, pos); + return bit; +} +#endif @@ -82,6 +82,12 @@ #define CRYPTO_STRING "" #endif +#ifdef HAVE_LIBMBEDCRYPTO +#define MBED_STRING "/mbedtls" +#else +#define MBED_STRING "" +#endif + #ifdef WITH_ZLIB #define ZLIB_STRING "/zlib" #else @@ -349,7 +355,7 @@ char *ssh_hostport(const char *host, int port){ */ const char *ssh_version(int req_version) { if (req_version <= LIBSSH_VERSION_INT) { - return SSH_STRINGIFY(LIBSSH_VERSION) GCRYPT_STRING CRYPTO_STRING + return SSH_STRINGIFY(LIBSSH_VERSION) GCRYPT_STRING CRYPTO_STRING MBED_STRING ZLIB_STRING; } diff --git a/src/options.c b/src/options.c index d2128c13..14b9e01e 100644 --- a/src/options.c +++ b/src/options.c @@ -1493,8 +1493,15 @@ int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type, key_type = ssh_key_type(key); switch (key_type) { case SSH_KEYTYPE_DSS: +#ifdef HAVE_DSA bind_key_loc = &sshbind->dsa; bind_key_path_loc = &sshbind->dsakey; +#else + ssh_set_error(sshbind, + SSH_FATAL, + "DSS key used and libssh compiled " + "without DSA support"); +#endif break; case SSH_KEYTYPE_ECDSA: #ifdef HAVE_ECC @@ -1550,7 +1557,14 @@ int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type, key_type = ssh_key_type(key); switch (key_type) { case SSH_KEYTYPE_DSS: +#ifdef HAVE_DSA bind_key_loc = &sshbind->dsa; +#else + ssh_set_error(sshbind, + SSH_FATAL, + "DSA key used and libssh compiled " + "without DSA support"); +#endif break; case SSH_KEYTYPE_ECDSA: #ifdef HAVE_ECC @@ -138,6 +138,16 @@ void ssh_key_clean (ssh_key key){ #ifdef HAVE_OPENSSL_ECC if(key->ecdsa) EC_KEY_free(key->ecdsa); #endif /* HAVE_OPENSSL_ECC */ +#elif defined HAVE_LIBMBEDCRYPTO + if (key->rsa != NULL) { + mbedtls_pk_free(key->rsa); + SAFE_FREE(key->rsa); + } + + if (key->ecdsa != NULL) { + mbedtls_ecdsa_free(key->ecdsa); + SAFE_FREE(key->ecdsa); + } #endif if (key->ed25519_privkey != NULL){ BURN_BUFFER(key->ed25519_privkey, sizeof(ed25519_privkey)); @@ -354,6 +364,8 @@ void ssh_signature_free(ssh_signature sig) gcry_sexp_release(sig->rsa_sig); #elif defined HAVE_LIBCRYPTO SAFE_FREE(sig->rsa_sig); +#elif defined HAVE_LIBMBEDCRYPTO + SAFE_FREE(sig->rsa_sig); #endif break; case SSH_KEYTYPE_ECDSA: @@ -361,6 +373,9 @@ void ssh_signature_free(ssh_signature sig) gcry_sexp_release(sig->ecdsa_sig); #elif defined(HAVE_LIBCRYPTO) && defined(HAVE_OPENSSL_ECC) ECDSA_SIG_free(sig->ecdsa_sig); +#elif defined HAVE_LIBMBEDCRYPTO + bignum_free(sig->ecdsa_sig.r); + bignum_free(sig->ecdsa_sig.s); #endif break; case SSH_KEYTYPE_ED25519: diff --git a/src/pki_mbedcrypto.c b/src/pki_mbedcrypto.c new file mode 100644 index 00000000..c3508540 --- /dev/null +++ b/src/pki_mbedcrypto.c @@ -0,0 +1,1304 @@ +/* + * This file is part of the SSH Library + * + * Copyright (c) 2017 Sartura d.o.o. + * + * Author: Juraj Vijtiuk <juraj.vijtiuk@sartura.hr> + * + * The SSH Library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * The SSH Library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the SSH Library; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +#include "config.h" + +#ifdef HAVE_LIBMBEDCRYPTO +#include <mbedtls/pk.h> +#include <mbedtls/error.h> + +#include "libssh/priv.h" +#include "libssh/pki.h" +#include "libssh/pki_priv.h" +#include "libssh/buffer.h" +#include "libssh/bignum.h" + +#define MAX_PASSPHRASE_SIZE 1024 +#define MAX_KEY_SIZE 32 + +ssh_string pki_private_key_to_pem(const ssh_key key, const char *passphrase, + ssh_auth_callback auth_fn, void *auth_data) +{ + (void) key; + (void) passphrase; + (void) auth_fn; + (void) auth_data; return NULL; +} + +static int pki_key_ecdsa_to_nid(mbedtls_ecdsa_context *ecdsa) +{ + mbedtls_ecp_group_id id; + + id = ecdsa->grp.id; + if (id == MBEDTLS_ECP_DP_SECP256R1) { + return NID_mbedtls_nistp256; + } else if (id == MBEDTLS_ECP_DP_SECP384R1) { + return NID_mbedtls_nistp384; + } else if (id == MBEDTLS_ECP_DP_SECP521R1) { + return NID_mbedtls_nistp521; + } + + return -1; +} + +ssh_key pki_private_key_from_base64(const char *b64_key, const char *passphrase, + ssh_auth_callback auth_fn, void *auth_data) +{ + ssh_key key = NULL; + mbedtls_pk_context *rsa = NULL; + mbedtls_pk_context *ecdsa = NULL; + ed25519_privkey *ed25519 = NULL; + enum ssh_keytypes_e type; + int valid; + /* mbedtls pk_parse_key expects strlen to count the 0 byte */ + size_t b64len = strlen(b64_key) + 1; + unsigned char tmp[MAX_PASSPHRASE_SIZE] = {0}; + + if (ssh_init() < 0) { + return NULL; + } + + type = pki_privatekey_type_from_string(b64_key); + if (type == SSH_KEYTYPE_UNKNOWN) { + SSH_LOG(SSH_LOG_WARN, "Unknown or invalid private key."); + return NULL; + } + + switch (type) { + case SSH_KEYTYPE_RSA: + case SSH_KEYTYPE_RSA1: + rsa = malloc(sizeof(mbedtls_pk_context)); + if (rsa == NULL) { + return NULL; + } + + mbedtls_pk_init(rsa); + + if (passphrase == NULL) { + if (auth_fn) { + valid = auth_fn("Passphrase for private key:", (char *) tmp, + MAX_PASSPHRASE_SIZE, 0, 0, auth_data); + if (valid < 0) { + return NULL; + } + /* TODO fix signedness and strlen */ + valid = mbedtls_pk_parse_key(rsa, + (const unsigned char *) b64_key, + b64len, tmp, + strnlen((const char *) tmp, MAX_PASSPHRASE_SIZE)); + } else { + valid = mbedtls_pk_parse_key(rsa, + (const unsigned char *) b64_key, + b64len, NULL, + 0); + } + } else { + valid = mbedtls_pk_parse_key(rsa, + (const unsigned char *) b64_key, b64len, + (const unsigned char *) passphrase, + strnlen(passphrase, MAX_PASSPHRASE_SIZE)); + } + + if (valid != 0) { + char error_buf[100]; + mbedtls_strerror(valid, error_buf, 100); + SSH_LOG(SSH_LOG_WARN,"Parsing private key %s", error_buf); + goto fail; + } + break; + case SSH_KEYTYPE_ECDSA: + ecdsa = malloc(sizeof(mbedtls_pk_context)); + if (ecdsa == NULL) { + return NULL; + } + + mbedtls_pk_init(ecdsa); + + if (passphrase == NULL) { + if (auth_fn) { + valid = auth_fn("Passphrase for private key:", (char *) tmp, + MAX_PASSPHRASE_SIZE, 0, 0, auth_data); + if (valid < 0) { + return NULL; + } + valid = mbedtls_pk_parse_key(ecdsa, + (const unsigned char *) b64_key, + b64len, tmp, + strnlen((const char *) tmp, MAX_PASSPHRASE_SIZE)); + } else { + valid = mbedtls_pk_parse_key(ecdsa, + (const unsigned char *) b64_key, + b64len, NULL, + 0); + } + } else { + valid = mbedtls_pk_parse_key(ecdsa, + (const unsigned char *) b64_key, b64len, + (const unsigned char *) passphrase, + strnlen(passphrase, MAX_PASSPHRASE_SIZE)); + } + + if (valid != 0) { + char error_buf[100]; + mbedtls_strerror(valid, error_buf, 100); + SSH_LOG(SSH_LOG_WARN,"Parsing private key %s", error_buf); + goto fail; + } + break; + case SSH_KEYTYPE_ED25519: + /* Cannot open ed25519 keys with libmbedcrypto */ + default: + SSH_LOG(SSH_LOG_WARN, "Unknown or invalid private key type %d", + type); + return NULL; + } + + key = ssh_key_new(); + if (key == NULL) { + goto fail; + } + + key->type = type; + key->type_c = ssh_key_type_to_char(type); + key->flags = SSH_KEY_FLAG_PRIVATE | SSH_KEY_FLAG_PUBLIC; + key->rsa = rsa; + if (ecdsa != NULL) { + mbedtls_ecp_keypair *keypair = mbedtls_pk_ec(*ecdsa); + + key->ecdsa = malloc(sizeof(mbedtls_ecdsa_context)); + if (key->ecdsa == NULL) { + goto fail; + } + + mbedtls_ecdsa_init(key->ecdsa); + mbedtls_ecdsa_from_keypair(key->ecdsa, keypair); + mbedtls_pk_free(ecdsa); + SAFE_FREE(ecdsa); + } else { + key->ecdsa = NULL; + } + key->ed25519_privkey = ed25519; + rsa = NULL; + ecdsa = NULL; + if (key->type == SSH_KEYTYPE_ECDSA) { + key->ecdsa_nid = pki_key_ecdsa_to_nid(key->ecdsa); + key->type_c = pki_key_ecdsa_nid_to_name(key->ecdsa_nid); + } + + return key; +fail: + ssh_key_free(key); + if (rsa != NULL) { + mbedtls_pk_free(rsa); + SAFE_FREE(rsa); + } + if (ecdsa != NULL) { + mbedtls_pk_free(ecdsa); + SAFE_FREE(ecdsa); + } + return NULL; +} + +int pki_pubkey_build_rsa(ssh_key key, ssh_string e, ssh_string n) +{ + mbedtls_rsa_context *rsa = NULL; + const mbedtls_pk_info_t *pk_info = NULL; + int rc; + + key->rsa = malloc(sizeof(mbedtls_pk_context)); + if (key->rsa == NULL) { + return SSH_ERROR; + } + + mbedtls_pk_init(key->rsa); + pk_info = mbedtls_pk_info_from_type(MBEDTLS_PK_RSA); + mbedtls_pk_setup(key->rsa, pk_info); + + if (mbedtls_pk_can_do(key->rsa, MBEDTLS_PK_RSA)) { + rsa = mbedtls_pk_rsa(*key->rsa); + rc = mbedtls_mpi_read_binary(&rsa->N, ssh_string_data(n), + ssh_string_len(n)); + if (rc != 0) { + return SSH_ERROR; + } + rc = mbedtls_mpi_read_binary(&rsa->E, ssh_string_data(e), + ssh_string_len(e)); + if (rc != 0) { + return SSH_ERROR; + } + + rsa->len = (mbedtls_mpi_bitlen(&rsa->N) + 7) >> 3; + } else { + return SSH_ERROR; + } + + return SSH_OK; +} + +ssh_key pki_key_dup(const ssh_key key, int demote) +{ + ssh_key new = NULL; + int rc; + const mbedtls_pk_info_t *pk_info = NULL; + + + new = ssh_key_new(); + if (new == NULL) { + return NULL; + } + + new->type = key->type; + new->type_c = key->type_c; + if (demote) { + new->flags = SSH_KEY_FLAG_PUBLIC; + } else { + new->flags = key->flags; + } + + + switch(key->type) { + case SSH_KEYTYPE_RSA: + case SSH_KEYTYPE_RSA1: { + mbedtls_rsa_context *rsa, *new_rsa; + + new->rsa = malloc(sizeof(mbedtls_pk_context)); + if (new->rsa == NULL) { + goto fail; + } + + mbedtls_pk_init(new->rsa); + pk_info = mbedtls_pk_info_from_type(MBEDTLS_PK_RSA); + mbedtls_pk_setup(new->rsa, pk_info); + + if (mbedtls_pk_can_do(key->rsa, MBEDTLS_PK_RSA) && + mbedtls_pk_can_do(new->rsa, MBEDTLS_PK_RSA)) { + rsa = mbedtls_pk_rsa(*key->rsa); + new_rsa = mbedtls_pk_rsa(*new->rsa); + + rc = mbedtls_mpi_copy(&new_rsa->N, &rsa->N); + if (rc != 0) { + goto fail; + } + + rc = mbedtls_mpi_copy(&new_rsa->E, &rsa->E); + if (rc != 0) { + goto fail; + } + new_rsa->len = (mbedtls_mpi_bitlen(&new_rsa->N) + 7) >> 3; + + if (!demote && (key->flags & SSH_KEY_FLAG_PRIVATE)) { + rc = mbedtls_mpi_copy(&new_rsa->D, &rsa->D); + if (rc != 0) { + goto fail; + } + + rc = mbedtls_mpi_copy(&new_rsa->P, &rsa->P); + if (rc != 0) { + goto fail; + } + + rc = mbedtls_mpi_copy(&new_rsa->Q, &rsa->Q); + if (rc != 0) { + goto fail; + } + + rc = mbedtls_mpi_copy(&new_rsa->DP, &rsa->DP); + if (rc != 0) { + goto fail; + } + + rc = mbedtls_mpi_copy(&new_rsa->DQ, &rsa->DQ); + if (rc != 0) { + goto fail; + } + + rc = mbedtls_mpi_copy(&new_rsa->QP, &rsa->QP); + if (rc != 0) { + goto fail; + } + } + } else { + goto fail; + } + + break; + } + case SSH_KEYTYPE_ECDSA: + new->ecdsa_nid = key->ecdsa_nid; + + new->ecdsa = malloc(sizeof(mbedtls_ecdsa_context)); + + if (new->ecdsa == NULL) { + goto fail; + } + + mbedtls_ecdsa_init(new->ecdsa); + + if (demote && ssh_key_is_private(key)) { + rc = mbedtls_ecp_copy(&new->ecdsa->Q, &key->ecdsa->Q); + if (rc != 0) { + goto fail; + } + + rc = mbedtls_ecp_group_copy(&new->ecdsa->grp, &key->ecdsa->grp); + if (rc != 0) { + goto fail; + } + } else { + mbedtls_ecdsa_from_keypair(new->ecdsa, key->ecdsa); + } + + break; + case SSH_KEYTYPE_ED25519: + rc = pki_ed25519_key_dup(new, key); + if (rc != SSH_OK) { + goto fail; + } + break; + default: + goto fail; + } + + return new; +fail: + ssh_key_free(new); + return NULL; +} + +int pki_key_generate_rsa(ssh_key key, int parameter) +{ + int rc; + const mbedtls_pk_info_t *info = NULL; + + key->rsa = malloc(sizeof(mbedtls_pk_context)); + if (key->rsa == NULL) { + return SSH_ERROR; + } + + mbedtls_pk_init(key->rsa); + + info = mbedtls_pk_info_from_type(MBEDTLS_PK_RSA); + rc = mbedtls_pk_setup(key->rsa, info); + if (rc != 0) { + return SSH_ERROR; + } + + if (mbedtls_pk_can_do(key->rsa, MBEDTLS_PK_RSA)) { + rc = mbedtls_rsa_gen_key(mbedtls_pk_rsa(*key->rsa), mbedtls_ctr_drbg_random, + &ssh_mbedtls_ctr_drbg, parameter, 65537); + if (rc != 0) { + mbedtls_pk_free(key->rsa); + return SSH_ERROR; + } + } + + return SSH_OK; +} + +int pki_key_compare(const ssh_key k1, const ssh_key k2, enum ssh_keycmp_e what) +{ + switch (k1->type) { + case SSH_KEYTYPE_RSA: + case SSH_KEYTYPE_RSA1: { + mbedtls_rsa_context *rsa1, *rsa2; + if (mbedtls_pk_can_do(k1->rsa, MBEDTLS_PK_RSA) && + mbedtls_pk_can_do(k2->rsa, MBEDTLS_PK_RSA)) { + if (mbedtls_pk_get_type(k1->rsa) != mbedtls_pk_get_type(k2->rsa) || + mbedtls_pk_get_bitlen(k1->rsa) != + mbedtls_pk_get_bitlen(k2->rsa)) { + return 1; + } + + rsa1 = mbedtls_pk_rsa(*k1->rsa); + rsa2 = mbedtls_pk_rsa(*k2->rsa); + if (mbedtls_mpi_cmp_mpi(&rsa1->N, &rsa2->N) != 0) { + return 1; + } + + if (mbedtls_mpi_cmp_mpi(&rsa1->E, &rsa2->E) != 0) { + return 1; + } + + if (what == SSH_KEY_CMP_PRIVATE) { + if (mbedtls_mpi_cmp_mpi(&rsa1->P, &rsa2->P) != 0) { + return 1; + } + + if (mbedtls_mpi_cmp_mpi(&rsa1->Q, &rsa2->Q) != 0) { + return 1; + } + } + } + break; + } + case SSH_KEYTYPE_ECDSA: + /* TODO: mbedTLS can't compare ecdsa keys. + mbedtls_ecdsa_context is actually a mbedtls_ecp_keypair, + so the private and public points and the group can be accessed + through the keypair. However, mbedtls has no method corresponding + to OpenSSL's EC_GROUP_cmp and EC_POITN_cmp, so the comparison + would have to be done manually. + */ + return 1; + case SSH_KEYTYPE_ED25519: + /* ed25519 keys handled globally */ + return 0; + default: + return 1; + } + + return 0; +} + +ssh_string make_ecpoint_string(const mbedtls_ecp_group *g, const + mbedtls_ecp_point *p) +{ + ssh_string s = NULL; + size_t len = 1; + int rc; + + s = ssh_string_new(len); + if (s == NULL) { + return NULL; + } + + rc = mbedtls_ecp_point_write_binary(g, p, MBEDTLS_ECP_PF_UNCOMPRESSED, + &len, ssh_string_data(s), ssh_string_len(s)); + if (rc == MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL) { + ssh_string_free(s); + + s = ssh_string_new(len); + if (s == NULL) { + return NULL; + } + + rc = mbedtls_ecp_point_write_binary(g, p, MBEDTLS_ECP_PF_UNCOMPRESSED, + &len, ssh_string_data(s), ssh_string_len(s)); + } + + if (rc != 0) { + ssh_string_free(s); + return NULL; + } + + if (len != ssh_string_len(s)) { + ssh_string_free(s); + return NULL; + } + + return s; +} + +static const char* pki_key_ecdsa_nid_to_char(int nid) +{ + switch (nid) { + case NID_mbedtls_nistp256: + return "nistp256"; + case NID_mbedtls_nistp384: + return "nistp384"; + case NID_mbedtls_nistp521: + return "nistp521"; + default: + break; + } + + return "unknown"; +} + +ssh_string pki_publickey_to_blob(const ssh_key key) +{ + ssh_buffer buffer = NULL; + ssh_string type_s = NULL; + ssh_string e = NULL; + ssh_string n = NULL; + ssh_string str = NULL; + int rc; + + buffer = ssh_buffer_new(); + if (buffer == NULL) { + return NULL; + } + + if (key->cert != NULL) { + rc = ssh_buffer_add_buffer(buffer, key->cert); + if (rc < 0) { + ssh_buffer_free(buffer); + return NULL; + } + + goto makestring; + } + + type_s = ssh_string_from_char(key->type_c); + if (type_s == NULL) { + ssh_buffer_free(buffer); + return NULL; + } + + rc = ssh_buffer_add_ssh_string(buffer, type_s); + ssh_string_free(type_s); + if (rc < 0) { + ssh_buffer_free(buffer); + return NULL; + } + + switch (key->type) { + case SSH_KEYTYPE_RSA: + case SSH_KEYTYPE_RSA1: { + mbedtls_rsa_context *rsa; + if (mbedtls_pk_can_do(key->rsa, MBEDTLS_PK_RSA) == 0) { + ssh_buffer_free(buffer); + return NULL; + } + + rsa = mbedtls_pk_rsa(*key->rsa); + + e = ssh_make_bignum_string(&rsa->E); + if (e == NULL) { + goto fail; + } + + n = ssh_make_bignum_string(&rsa->N); + if (n == NULL) { + goto fail; + } + + if (ssh_buffer_add_ssh_string(buffer, e) < 0) { + goto fail; + } + + if (ssh_buffer_add_ssh_string(buffer, n) < 0) { + goto fail; + } + + ssh_string_burn(e); + ssh_string_free(e); + e = NULL; + ssh_string_burn(n); + ssh_string_free(n); + n = NULL; + + break; + } + case SSH_KEYTYPE_ECDSA: + rc = ssh_buffer_reinit(buffer); + if (rc < 0) { + ssh_buffer_free(buffer); + return NULL; + } + + type_s = + ssh_string_from_char(pki_key_ecdsa_nid_to_name(key->ecdsa_nid)); + if (type_s == NULL) { + ssh_buffer_free(buffer); + return NULL; + } + + rc = ssh_buffer_add_ssh_string(buffer, type_s); + ssh_string_free(type_s); + if (rc < 0) { + ssh_buffer_free(buffer); + return NULL; + } + + type_s = + ssh_string_from_char(pki_key_ecdsa_nid_to_char(key->ecdsa_nid)); + if (type_s == NULL) { + ssh_buffer_free(buffer); + return NULL; + } + + rc = ssh_buffer_add_ssh_string(buffer, type_s); + ssh_string_free(type_s); + if (rc < 0) { + ssh_buffer_free(buffer); + return NULL; + } + + e = make_ecpoint_string(&key->ecdsa->grp, &key->ecdsa->Q); + + if (e == NULL) { + ssh_buffer_free(buffer); + return NULL; + } + + rc = ssh_buffer_add_ssh_string(buffer, e); + if (rc < 0) { + goto fail; + } + + ssh_string_burn(e); + ssh_string_free(e); + e = NULL; + + break; + case SSH_KEYTYPE_ED25519: + rc = pki_ed25519_public_key_to_blob(buffer, key); + if (rc != SSH_OK) { + goto fail; + } + break; + default: + goto fail; + } +makestring: + str = ssh_string_new(ssh_buffer_get_len(buffer)); + if (str == NULL) { + goto fail; + } + + rc = ssh_string_fill(str, ssh_buffer_get(buffer), + ssh_buffer_get_len(buffer)); + if (rc < 0) { + goto fail; + } + + ssh_buffer_free(buffer); + return str; +fail: + ssh_buffer_free(buffer); + ssh_string_burn(str); + ssh_string_free(str); + ssh_string_burn(e); + ssh_string_free(e); + ssh_string_burn(n); + ssh_string_free(n); + + return NULL; +} + +int pki_export_pubkey_rsa1(const ssh_key key, const char *host, char *rsa1, + size_t rsa1_len) +{ + char *e = NULL; + char *n = NULL; + int rsa_size = mbedtls_pk_get_bitlen(key->rsa); + mbedtls_rsa_context *rsa = NULL; + + if (!mbedtls_pk_can_do(key->rsa, MBEDTLS_PK_RSA)) { + return SSH_ERROR; + } + + rsa = mbedtls_pk_rsa(*key->rsa); + + n = bignum_bn2dec(&rsa->N); + if (n == NULL) { + return SSH_ERROR; + } + + e = bignum_bn2dec(&rsa->E); + if (e == NULL) { + return SSH_ERROR; + } + + snprintf(rsa1, rsa1_len, "%s %d %s %s\n", + host, rsa_size << 3, e, n); + + SAFE_FREE(e); + SAFE_FREE(n); + return SSH_OK; +} + +ssh_string pki_signature_to_blob(const ssh_signature sig) +{ + ssh_string sig_blob = NULL; + + switch(sig->type) { + case SSH_KEYTYPE_RSA: + case SSH_KEYTYPE_RSA1: + sig_blob = ssh_string_copy(sig->rsa_sig); + break; + case SSH_KEYTYPE_ECDSA: { + ssh_string r; + ssh_string s; + ssh_buffer b; + int rc; + + b = ssh_buffer_new(); + if (b == NULL) { + return NULL; + } + + r = ssh_make_bignum_string(sig->ecdsa_sig.r); + if (r == NULL) { + ssh_buffer_free(b); + return NULL; + } + + rc = ssh_buffer_add_ssh_string(b, r); + ssh_string_free(r); + if (rc < 0) { + ssh_buffer_free(b); + return NULL; + } + + s = ssh_make_bignum_string(sig->ecdsa_sig.s); + if (s == NULL) { + ssh_buffer_free(b); + return NULL; + } + + rc = ssh_buffer_add_ssh_string(b, s); + ssh_string_free(s); + if (rc < 0) { + ssh_buffer_free(b); + return NULL; + } + + sig_blob = ssh_string_new(ssh_buffer_get_len(b)); + if (sig_blob == NULL) { + ssh_buffer_free(b); + return NULL; + } + + ssh_string_fill(sig_blob, ssh_buffer_get(b), ssh_buffer_get_len(b)); + ssh_buffer_free(b); + break; + } + case SSH_KEYTYPE_ED25519: + sig_blob = pki_ed25519_sig_to_blob(sig); + break; + default: + SSH_LOG(SSH_LOG_WARN, "Unknown signature key type: %s", + sig->type_c); + return NULL; + } + + return sig_blob; +} + +static ssh_signature pki_signature_from_rsa_blob(const ssh_key pubkey, const + ssh_string sig_blob, ssh_signature sig) +{ + size_t pad_len = 0; + char *blob_orig = NULL; + char *blob_padded_data = NULL; + ssh_string sig_blob_padded = NULL; + + size_t rsalen = 0; + size_t len = ssh_string_len(sig_blob); + + if (pubkey->rsa == NULL) { + SSH_LOG(SSH_LOG_WARN, "Pubkey RSA field NULL"); + goto errout; + } + + rsalen = mbedtls_pk_get_bitlen(pubkey->rsa) / 8; + if (len > rsalen) { + SSH_LOG(SSH_LOG_WARN, + "Signature is too big: %lu > %lu", + (unsigned long) len, + (unsigned long) rsalen); + goto errout; + } +#ifdef DEBUG_CRYPTO + SSH_LOG(SSH_LOG_WARN, "RSA signature len: %lu", (unsigned long)len); + ssh_print_hexa("RSA signature", ssh_string_data(sig_blob), len); +#endif + + if (len == rsalen) { + sig->rsa_sig = ssh_string_copy(sig_blob); + } else { + SSH_LOG(SSH_LOG_DEBUG, "RSA signature len %lu < %lu", + (unsigned long) len, + (unsigned long) rsalen); + pad_len = rsalen - len; + + sig_blob_padded = ssh_string_new(rsalen); + if (sig_blob_padded == NULL) { + goto errout; + } + + blob_padded_data = (char *) ssh_string_data(sig_blob_padded); + blob_orig = (char *) ssh_string_data(sig_blob); + + BURN_BUFFER(blob_padded_data, pad_len); + memcpy(blob_padded_data + pad_len, blob_orig, len); + + sig->rsa_sig = sig_blob_padded; + } + + return sig; + +errout: + ssh_signature_free(sig); + return NULL; +} +ssh_signature pki_signature_from_blob(const ssh_key pubkey, const ssh_string + sig_blob, enum ssh_keytypes_e type) +{ + ssh_signature sig = NULL; + int rc; + + sig = ssh_signature_new(); + if (sig == NULL) { + return NULL; + } + + sig->type = type; + sig->type_c = ssh_key_type_to_char(type); + + switch(type) { + case SSH_KEYTYPE_RSA: + case SSH_KEYTYPE_RSA1: + sig = pki_signature_from_rsa_blob(pubkey, sig_blob, sig); + break; + case SSH_KEYTYPE_ECDSA: { + ssh_buffer b; + ssh_string r; + ssh_string s; + size_t rlen; + + b = ssh_buffer_new(); + if (b == NULL) { + ssh_signature_free(sig); + return NULL; + } + + rc = ssh_buffer_add_data(b, ssh_string_data(sig_blob), + ssh_string_len(sig_blob)); + + if (rc < 0) { + ssh_buffer_free(b); + ssh_signature_free(sig); + return NULL; + } + + r = ssh_buffer_get_ssh_string(b); + if (r == NULL) { + ssh_buffer_free(b); + ssh_signature_free(sig); + return NULL; + } +#ifdef DEBUG_CRYPTO + ssh_print_hexa("r", ssh_string_data(r), ssh_string_len(r)); +#endif + sig->ecdsa_sig.r = ssh_make_string_bn(r); + ssh_string_burn(r); + ssh_string_free(r); + if (sig->ecdsa_sig.r == NULL) { + ssh_buffer_free(b); + ssh_signature_free(sig); + return NULL; + } + + s = ssh_buffer_get_ssh_string(b); + rlen = ssh_buffer_get_len(b); + ssh_buffer_free(b); + if (s == NULL) { + ssh_signature_free(sig); + return NULL; + } + +#ifdef DEBUG_CRYPTO + ssh_print_hexa("s", ssh_string_data(s), ssh_string_len(s)); +#endif + sig->ecdsa_sig.s = ssh_make_string_bn(s); + ssh_string_burn(s); + ssh_string_free(s); + if (sig->ecdsa_sig.s == NULL) { + ssh_signature_free(sig); + return NULL; + } + + if (rlen != 0) { + SSH_LOG(SSH_LOG_WARN, "Signature has remaining bytes in inner " + "sigblob: %lu", + (unsigned long)rlen); + ssh_signature_free(sig); + return NULL; + } + + break; + } + case SSH_KEYTYPE_ED25519: + rc = pki_ed25519_sig_from_blob(sig, sig_blob); + if (rc == SSH_ERROR) { + ssh_signature_free(sig); + return NULL; + } + break; + default: + SSH_LOG(SSH_LOG_WARN, "Unknown signature type"); + return NULL; + } + + return sig; +} + +int pki_signature_verify(ssh_session session, const ssh_signature sig, const + ssh_key key, const unsigned char *hash, size_t hlen) +{ + int rc; + + switch (key->type) { + case SSH_KEYTYPE_RSA: + case SSH_KEYTYPE_RSA1: + rc = mbedtls_pk_verify(key->rsa, MBEDTLS_MD_SHA1, hash, hlen, + ssh_string_data(sig->rsa_sig), + ssh_string_len(sig->rsa_sig)); + if (rc != 0) { + char error_buf[100]; + mbedtls_strerror(rc, error_buf, 100); + ssh_set_error(session, SSH_FATAL, "RSA error: %s", error_buf); + return SSH_ERROR; + } + break; + case SSH_KEYTYPE_ECDSA: + rc = mbedtls_ecdsa_verify(&key->ecdsa->grp, hash, hlen, + &key->ecdsa->Q, sig->ecdsa_sig.r, sig->ecdsa_sig.s); + if (rc != 0) { + char error_buf[100]; + mbedtls_strerror(rc, error_buf, 100); + ssh_set_error(session, SSH_FATAL, "RSA error: %s", error_buf); + return SSH_ERROR; + + } + break; + case SSH_KEYTYPE_ED25519: + rc = pki_ed25519_verify(key, sig, hash, hlen); + if (rc != SSH_OK) { + ssh_set_error(session, SSH_FATAL, + "ed25519 signature verification error"); + return SSH_ERROR; + } + break; + default: + ssh_set_error(session, SSH_FATAL, "Unknown public key type"); + return SSH_ERROR; + } + + return SSH_OK; +} + +static ssh_string rsa_do_sign(const unsigned char *digest, int dlen, + mbedtls_pk_context *privkey) +{ + ssh_string sig_blob = NULL; + unsigned char *sig = NULL; + size_t slen; + int ok; + + sig = malloc(mbedtls_pk_get_bitlen(privkey) / 8); + if (sig == NULL) { + return NULL; + } + + ok = mbedtls_pk_sign(privkey, MBEDTLS_MD_SHA1, digest, dlen, sig, &slen, + mbedtls_ctr_drbg_random, &ssh_mbedtls_ctr_drbg); + + if (ok != 0) { + SAFE_FREE(sig); + return NULL; + } + + sig_blob = ssh_string_new(slen); + if (sig_blob == NULL) { + SAFE_FREE(sig); + return NULL; + } + + ssh_string_fill(sig_blob, sig, slen); + memset(sig, 'd', slen); + SAFE_FREE(sig); + + return sig_blob; +} + + +ssh_signature pki_do_sign(const ssh_key privkey, const unsigned char *hash, + size_t hlen) +{ + ssh_signature sig = NULL; + int rc; + + sig = ssh_signature_new(); + if (sig == NULL) { + return NULL; + } + + sig->type = privkey->type; + sig->type_c = privkey->type_c; + + switch(privkey->type) { + case SSH_KEYTYPE_RSA: + case SSH_KEYTYPE_RSA1: + sig->rsa_sig = rsa_do_sign(hash, hlen, privkey->rsa); + if (sig->rsa_sig == NULL) { + ssh_signature_free(sig); + return NULL; + } + break; + case SSH_KEYTYPE_ECDSA: + sig->ecdsa_sig.r = bignum_new(); + if (sig->ecdsa_sig.r == NULL) { + return NULL; + } + + sig->ecdsa_sig.s = bignum_new(); + if (sig->ecdsa_sig.s == NULL) { + bignum_free(sig->ecdsa_sig.r); + return NULL; + } + + rc = mbedtls_ecdsa_sign(&privkey->ecdsa->grp, sig->ecdsa_sig.r, + sig->ecdsa_sig.s, &privkey->ecdsa->d, hash, hlen, + mbedtls_ctr_drbg_random, &ssh_mbedtls_ctr_drbg); + if (rc != 0) { + ssh_signature_free(sig); + return NULL; + } + break; + case SSH_KEYTYPE_ED25519: + rc = pki_ed25519_sign(privkey, sig, hash, hlen); + if (rc != SSH_OK) { + ssh_signature_free(sig); + return NULL; + } + break; + default: + ssh_signature_free(sig); + return NULL; + + } + + return sig; +} + +#ifdef WITH_SERVER +ssh_signature pki_do_sign_sessionid(const ssh_key key, const unsigned char + *hash, size_t hlen) +{ + ssh_signature sig = NULL; + int rc; + + sig = ssh_signature_new(); + if (sig == NULL) { + return NULL; + } + sig->type = key->type; + sig->type_c = key->type_c; + + switch (key->type) { + case SSH_KEYTYPE_RSA: + case SSH_KEYTYPE_RSA1: + sig->rsa_sig = rsa_do_sign(hash, hlen, key->rsa); + if (sig->rsa_sig == NULL) { + ssh_signature_free(sig); + return NULL; + } + break; + case SSH_KEYTYPE_ECDSA: + sig->ecdsa_sig.r = bignum_new(); + if (sig->ecdsa_sig.r == NULL) { + return NULL; + } + + sig->ecdsa_sig.s = bignum_new(); + if (sig->ecdsa_sig.s == NULL) { + bignum_free(sig->ecdsa_sig.r); + return NULL; + } + + rc = mbedtls_ecdsa_sign(&key->ecdsa->grp, sig->ecdsa_sig.r, + sig->ecdsa_sig.s, &key->ecdsa->d, hash, hlen, + mbedtls_ctr_drbg_random, &ssh_mbedtls_ctr_drbg); + if (rc != 0) { + ssh_signature_free(sig); + return NULL; + } + break; + case SSH_KEYTYPE_ED25519: + /* ED25519 handled in caller */ + default: + ssh_signature_free(sig); + return NULL; + } + + return sig; +} +#endif /* WITH_SERVER */ + +const char *pki_key_ecdsa_nid_to_name(int nid) +{ + switch (nid) { + case NID_mbedtls_nistp256: + return "ecdsa-sha2-nistp256"; + case NID_mbedtls_nistp384: + return "ecdsa-sha2-nistp384"; + case NID_mbedtls_nistp521: + return "ecdsa-sha2-nistp521"; + default: + break; + } + + return "unknown"; +} + +int pki_key_ecdsa_nid_from_name(const char *name) +{ + if (strcmp(name, "nistp256") == 0) { + return NID_mbedtls_nistp256; + } else if (strcmp(name, "nistp384") == 0) { + return NID_mbedtls_nistp384; + } else if (strcmp(name, "nistp521") == 0) { + return NID_mbedtls_nistp521; + } + + return -1; +} + +static mbedtls_ecp_group_id pki_key_ecdsa_nid_to_mbed_gid(int nid) +{ + switch (nid) { + case NID_mbedtls_nistp256: + return MBEDTLS_ECP_DP_SECP256R1; + case NID_mbedtls_nistp384: + return MBEDTLS_ECP_DP_SECP384R1; + case NID_mbedtls_nistp521: + return MBEDTLS_ECP_DP_SECP521R1; + } + + return MBEDTLS_ECP_DP_NONE; +} + +int pki_pubkey_build_ecdsa(ssh_key key, int nid, ssh_string e) +{ + int rc; + mbedtls_ecp_keypair keypair; + mbedtls_ecp_group group; + mbedtls_ecp_point Q; + + key->ecdsa_nid = nid; + key->type_c = pki_key_ecdsa_nid_to_name(nid); + + key->ecdsa = malloc(sizeof(mbedtls_ecdsa_context)); + if (key->ecdsa == NULL) { + return SSH_ERROR; + } + + mbedtls_ecdsa_init(key->ecdsa); + mbedtls_ecp_keypair_init(&keypair); + mbedtls_ecp_group_init(&group); + mbedtls_ecp_point_init(&Q); + + rc = mbedtls_ecp_group_load(&group, + pki_key_ecdsa_nid_to_mbed_gid(nid)); + if (rc != 0) { + goto fail; + } + + rc = mbedtls_ecp_point_read_binary(&group, &Q, ssh_string_data(e), + ssh_string_len(e)); + if (rc != 0) { + goto fail; + } + + rc = mbedtls_ecp_copy(&keypair.Q, &Q); + if (rc != 0) { + goto fail; + } + + rc = mbedtls_ecp_group_copy(&keypair.grp, &group); + if (rc != 0) { + goto fail; + } + + mbedtls_mpi_init(&keypair.d); + + rc = mbedtls_ecdsa_from_keypair(key->ecdsa, &keypair); + if (rc != 0) { + goto fail; + } + + mbedtls_ecp_point_free(&Q); + mbedtls_ecp_group_free(&group); + mbedtls_ecp_keypair_free(&keypair); + return SSH_OK; +fail: + mbedtls_ecdsa_free(key->ecdsa); + mbedtls_ecp_point_free(&Q); + mbedtls_ecp_group_free(&group); + mbedtls_ecp_keypair_free(&keypair); + SAFE_FREE(key->ecdsa); + return SSH_ERROR; +} + +int pki_key_generate_ecdsa(ssh_key key, int parameter) +{ + int nid; + int ok; + + switch (parameter) { + case 384: + nid = NID_mbedtls_nistp384; + break; + case 512: + nid = NID_mbedtls_nistp521; + break; + case 256: + default: + nid = NID_mbedtls_nistp256; + break; + } + + key->ecdsa_nid = nid; + key->type = SSH_KEYTYPE_ECDSA; + key->type_c = pki_key_ecdsa_nid_to_name(nid); + + key->ecdsa = malloc(sizeof(mbedtls_ecdsa_context)); + if (key->ecdsa == NULL) { + return SSH_ERROR; + } + + mbedtls_ecdsa_init(key->ecdsa); + + ok = mbedtls_ecdsa_genkey(key->ecdsa, pki_key_ecdsa_nid_to_mbed_gid(nid), + mbedtls_ctr_drbg_random, &ssh_mbedtls_ctr_drbg); + + if (ok != 0) { + mbedtls_ecdsa_free(key->ecdsa); + SAFE_FREE(key->ecdsa); + } + + return SSH_OK; +} + +int pki_pubkey_build_dss(ssh_key key, ssh_string p, ssh_string q, ssh_string g, + ssh_string pubkey) +{ + (void) key; + (void) p; + (void) q; + (void) g; + (void) pubkey; + return SSH_ERROR; +} + +int pki_key_generate_dss(ssh_key key, int parameter) +{ + (void) key; + (void) parameter; + return SSH_ERROR; +} +#endif /* HAVE_LIBMBEDCRYPTO */ diff --git a/src/server.c b/src/server.c index b2552eaa..b31a8e42 100644 --- a/src/server.c +++ b/src/server.c @@ -107,6 +107,7 @@ static int server_set_kex(ssh_session session) { ",%s", session->srv.ecdsa_key->type_c); } #endif +#ifdef HAVE_DSA if (session->srv.dsa_key != NULL) { len = strlen(hostkeys); keytype = ssh_key_type(session->srv.dsa_key); @@ -114,6 +115,7 @@ static int server_set_kex(ssh_session session) { snprintf(hostkeys + len, sizeof(hostkeys) - len, ",%s", ssh_key_type_to_char(keytype)); } +#endif if (session->srv.rsa_key != NULL) { len = strlen(hostkeys); keytype = ssh_key_type(session->srv.rsa_key); diff --git a/src/session.c b/src/session.c index bb01f169..b372dad6 100644 --- a/src/session.c +++ b/src/session.c @@ -148,6 +148,7 @@ ssh_session ssh_new(void) { goto err; } +#ifdef HAVE_DSA id = strdup("%d/id_dsa"); if (id == NULL) { goto err; @@ -156,6 +157,7 @@ ssh_session ssh_new(void) { if (rc == SSH_ERROR) { goto err; } +#endif id = strdup("%d/identity"); if (id == NULL) { diff --git a/src/threads.c b/src/threads.c index 062c3b84..b85ac756 100644 --- a/src/threads.c +++ b/src/threads.c @@ -33,6 +33,10 @@ #include "libssh/crypto.h" #include "libssh/threads.h" +#ifdef HAVE_LIBMBEDCRYPTO +#include <mbedtls/threading.h> +#endif + static int threads_noop (void **lock){ (void)lock; return 0; @@ -100,6 +104,28 @@ static int libgcrypt_thread_init(void){ return SSH_OK; } #endif /* GCRYPT_VERSION_NUMBER */ +#elif defined HAVE_LIBMBEDCRYPTO +static int libmbedcrypto_thread_init(void) +{ + if (user_callbacks == NULL) { + return SSH_ERROR; + } + + if (user_callbacks == &ssh_threads_noop) { + return SSH_OK; + } +#ifdef MBEDTLS_THREADING_ALT + else { + mbedtls_threading_set_alt(user_callbacks->mutex_init, + user_callbacks->mutex_destroy, user_callbacks->mutex_lock, + user_callbacks->mutex_unlock); + } +#elif defined MBEDTLS_THREADING_PTHREAD + return SSH_OK; +#else + return SSH_ERROR; +#endif +} #else /* HAVE_LIBGCRYPT */ /* Libcrypto specific stuff */ @@ -181,6 +207,8 @@ int ssh_threads_init(void){ /* Then initialize the crypto libraries threading callbacks */ #ifdef HAVE_LIBGCRYPT ret = libgcrypt_thread_init(); +#elif HAVE_LIBMBEDCRYPTO + ret = libmbedcrypto_thread_init(); #else /* Libcrypto */ ret = libcrypto_thread_init(); #endif @@ -191,6 +219,10 @@ int ssh_threads_init(void){ void ssh_threads_finalize(void){ #ifdef HAVE_LIBGCRYPT +#elif HAVE_LIBMBEDCRYPTO +#ifdef MBEDTLS_THREADING_ALT + mbedtls_threading_free_alt(); +#endif #else libcrypto_thread_finalize(); #endif diff --git a/tests/client/torture_knownhosts.c b/tests/client/torture_knownhosts.c index 1702b467..cfa47deb 100644 --- a/tests/client/torture_knownhosts.c +++ b/tests/client/torture_knownhosts.c @@ -40,6 +40,7 @@ "YgIytryNn7LLiwYfoSxvWigFrTTZsrVtCOYyNgklmffpGdzuC43wdANvTewfI9G" \ "o71r8EXmEc228CrYPmb8Scv3mpXFK/BosohSGkPlEHu9lf3YjnknBicDaVtJOYp" \ "wnXJPjZo2EhG79HxDRpjJHH" +#ifdef HAVE_DSA #define BADDSA "AAAAB3NzaC1kc3MAAACBAITDKqGQ5aC5wHySG6ZdL1+BVBY2nLP5vzw3i3pvZfP" \ "yNUS0UCwrt5pajsMvDRGXXebTJhWVonDnv8tpSgiuIBXMZrma8CU1KCFGRzwb/n8" \ "cc5tJmIphlOUTrObjBmsRz7u1eZmoaddXC9ask6BNnt0DmhzYi2esL3mbardy8IN" \ @@ -50,6 +51,7 @@ "EcxqLVllrNEvd2EGD9p16BYO2yaalYon8im59PtOcul2ay5XQ6rVDQ2T0pgNUpsI" \ "h0dSi8VJXI1wes5HTyLsv9VBmU1uCXUUvufoQKfF/OcSH0ufcCpnd62g1/adZcy2" \ "WJg==" +#endif static int sshd_setup(void **state) { @@ -187,6 +189,7 @@ static void torture_knownhosts_fail(void **state) { assert_int_equal(rc, SSH_SERVER_KNOWN_CHANGED); } +#ifdef HAVE_DSA static void torture_knownhosts_other(void **state) { struct torture_state *s = *state; ssh_session session = s->ssh.session; @@ -272,6 +275,7 @@ static void torture_knownhosts_other_auto(void **state) { /* session will be freed by session_teardown() */ } +#endif static void torture_knownhosts_conflict(void **state) { struct torture_state *s = *state; @@ -298,7 +302,9 @@ static void torture_knownhosts_conflict(void **state) { file = fopen(known_hosts_file, "w"); assert_true(file != NULL); fprintf(file, "127.0.0.10 ssh-rsa %s\n", BADRSA); +#ifdef HAVE_DSA fprintf(file, "127.0.0.10 ssh-dss %s\n", BADDSA); +#endif fclose(file); rc = ssh_connect(session); @@ -356,15 +362,21 @@ static void torture_knownhosts_precheck(void **state) { file = fopen(known_hosts_file, "w"); assert_true(file != NULL); fprintf(file, "127.0.0.10 ssh-rsa %s\n", BADRSA); +#ifdef HAVE_DSA fprintf(file, "127.0.0.10 ssh-dss %s\n", BADDSA); +#endif fclose(file); kex = ssh_knownhosts_algorithms(session); assert_true(kex != NULL); assert_string_equal(kex[0],"ssh-rsa"); +#ifdef HAVE_DSA assert_string_equal(kex[1],"ssh-dss"); assert_true(kex[2]==NULL); free(kex[1]); +#else + assert_true(kex[1]==NULL); +#endif free(kex[0]); free(kex); } @@ -378,12 +390,14 @@ int torture_run_tests(void) { cmocka_unit_test_setup_teardown(torture_knownhosts_fail, session_setup, session_teardown), +#ifdef HAVE_DSA cmocka_unit_test_setup_teardown(torture_knownhosts_other, session_setup, session_teardown), cmocka_unit_test_setup_teardown(torture_knownhosts_other_auto, session_setup, session_teardown), +#endif cmocka_unit_test_setup_teardown(torture_knownhosts_conflict, session_setup, session_teardown), diff --git a/tests/pkd/pkd_daemon.c b/tests/pkd/pkd_daemon.c index 9860ca56..a128c8e9 100644 --- a/tests/pkd/pkd_daemon.c +++ b/tests/pkd/pkd_daemon.c @@ -253,8 +253,10 @@ static int pkd_exec_hello(int fd, struct pkd_daemon_args *args) { if (type == PKD_RSA) { opts = SSH_BIND_OPTIONS_RSAKEY; +#ifdef HAVE_DSA } else if (type == PKD_DSA) { opts = SSH_BIND_OPTIONS_DSAKEY; +#endif } else if (type == PKD_ECDSA) { opts = SSH_BIND_OPTIONS_ECDSAKEY; } else { diff --git a/tests/pkd/pkd_daemon.h b/tests/pkd/pkd_daemon.h index 7f553fdf..3107ed1e 100644 --- a/tests/pkd/pkd_daemon.h +++ b/tests/pkd/pkd_daemon.h @@ -10,7 +10,9 @@ enum pkd_hostkey_type_e { PKD_RSA, +#ifdef HAVE_DSA PKD_DSA, +#endif PKD_ECDSA }; diff --git a/tests/pkd/pkd_hello.c b/tests/pkd/pkd_hello.c index 4db8ee5c..e0c0cbf6 100644 --- a/tests/pkd/pkd_hello.c +++ b/tests/pkd/pkd_hello.c @@ -146,12 +146,14 @@ static int torture_pkd_setup_rsa(void **state) { return 0; } +#ifdef HAVE_DSA static int torture_pkd_setup_dsa(void **state) { setup_dsa_key(); *state = (void *) torture_pkd_setup(PKD_DSA, LIBSSH_DSA_TESTKEY); return 0; } +#endif static int torture_pkd_setup_ecdsa_256(void **state) { setup_ecdsa_keys(); @@ -178,6 +180,7 @@ static int torture_pkd_setup_ecdsa_521(void **state) { * Test matrices: f(clientname, testname, ssh-command, setup-function, teardown-function). */ +#ifdef HAVE_DSA #define PKDTESTS_DEFAULT(f, client, cmd) \ /* Default passes by server key type. */ \ f(client, rsa_default, cmd, setup_rsa, teardown) \ @@ -185,7 +188,16 @@ static int torture_pkd_setup_ecdsa_521(void **state) { f(client, ecdsa_256_default, cmd, setup_ecdsa_256, teardown) \ f(client, ecdsa_384_default, cmd, setup_ecdsa_384, teardown) \ f(client, ecdsa_521_default, cmd, setup_ecdsa_521, teardown) +#else +#define PKDTESTS_DEFAULT(f, client, cmd) \ + /* Default passes by server key type. */ \ + f(client, rsa_default, cmd, setup_rsa, teardown) \ + f(client, ecdsa_256_default, cmd, setup_ecdsa_256, teardown) \ + f(client, ecdsa_384_default, cmd, setup_ecdsa_384, teardown) \ + f(client, ecdsa_521_default, cmd, setup_ecdsa_521, teardown) +#endif +#ifdef HAVE_DSA #define PKDTESTS_KEX(f, client, kexcmd) \ /* Kex algorithms. */ \ f(client, rsa_curve25519_sha256, kexcmd("curve25519-sha256@libssh.org"), setup_rsa, teardown) \ @@ -218,7 +230,28 @@ static int torture_pkd_setup_ecdsa_521(void **state) { f(client, ecdsa_521_ecdh_sha2_nistp521, kexcmd("ecdh-sha2-nistp521 "), setup_ecdsa_521, teardown) \ f(client, ecdsa_521_diffie_hellman_group14_sha1, kexcmd("diffie-hellman-group14-sha1"), setup_ecdsa_521, teardown) \ f(client, ecdsa_521_diffie_hellman_group1_sha1, kexcmd("diffie-hellman-group1-sha1"), setup_ecdsa_521, teardown) +#else +#define PKDTESTS_KEX(f, client, kexcmd) \ + /* Kex algorithms. */ \ + f(client, rsa_curve25519_sha256, kexcmd("curve25519-sha256@libssh.org"), setup_rsa, teardown) \ + f(client, rsa_ecdh_sha2_nistp256, kexcmd("ecdh-sha2-nistp256 "), setup_rsa, teardown) \ + f(client, rsa_diffie_hellman_group14_sha1, kexcmd("diffie-hellman-group14-sha1"), setup_rsa, teardown) \ + f(client, rsa_diffie_hellman_group1_sha1, kexcmd("diffie-hellman-group1-sha1"), setup_rsa, teardown) \ + f(client, ecdsa_256_curve25519_sha256, kexcmd("curve25519-sha256@libssh.org"), setup_ecdsa_256, teardown) \ + f(client, ecdsa_256_ecdh_sha2_nistp256, kexcmd("ecdh-sha2-nistp256 "), setup_ecdsa_256, teardown) \ + f(client, ecdsa_256_diffie_hellman_group14_sha1, kexcmd("diffie-hellman-group14-sha1"), setup_ecdsa_256, teardown) \ + f(client, ecdsa_256_diffie_hellman_group1_sha1, kexcmd("diffie-hellman-group1-sha1"), setup_ecdsa_256, teardown) \ + f(client, ecdsa_384_curve25519_sha256, kexcmd("curve25519-sha256@libssh.org"), setup_ecdsa_384, teardown) \ + f(client, ecdsa_384_ecdh_sha2_nistp256, kexcmd("ecdh-sha2-nistp256 "), setup_ecdsa_384, teardown) \ + f(client, ecdsa_384_diffie_hellman_group14_sha1, kexcmd("diffie-hellman-group14-sha1"), setup_ecdsa_384, teardown) \ + f(client, ecdsa_384_diffie_hellman_group1_sha1, kexcmd("diffie-hellman-group1-sha1"), setup_ecdsa_384, teardown) \ + f(client, ecdsa_521_curve25519_sha256, kexcmd("curve25519-sha256@libssh.org"), setup_ecdsa_521, teardown) \ + f(client, ecdsa_521_ecdh_sha2_nistp256, kexcmd("ecdh-sha2-nistp256 "), setup_ecdsa_521, teardown) \ + f(client, ecdsa_521_diffie_hellman_group14_sha1, kexcmd("diffie-hellman-group14-sha1"), setup_ecdsa_521, teardown) \ + f(client, ecdsa_521_diffie_hellman_group1_sha1, kexcmd("diffie-hellman-group1-sha1"), setup_ecdsa_521, teardown) +#endif +#ifdef HAVE_DSA #define PKDTESTS_CIPHER(f, client, ciphercmd) \ /* Ciphers. */ \ f(client, rsa_3des_cbc, ciphercmd("3des-cbc"), setup_rsa, teardown) \ @@ -251,7 +284,36 @@ static int torture_pkd_setup_ecdsa_521(void **state) { f(client, ecdsa_521_aes256_cbc, ciphercmd("aes256-cbc"), setup_ecdsa_521, teardown) \ f(client, ecdsa_521_aes256_ctr, ciphercmd("aes256-ctr"), setup_ecdsa_521, teardown) \ f(client, ecdsa_521_blowfish_cbc, ciphercmd("blowfish-cbc"), setup_ecdsa_521, teardown) +#else +#define PKDTESTS_CIPHER(f, client, ciphercmd) \ + /* Ciphers. */ \ + f(client, rsa_3des_cbc, ciphercmd("3des-cbc"), setup_rsa, teardown) \ + f(client, rsa_aes128_cbc, ciphercmd("aes128-cbc"), setup_rsa, teardown) \ + f(client, rsa_aes128_ctr, ciphercmd("aes128-ctr"), setup_rsa, teardown) \ + f(client, rsa_aes256_cbc, ciphercmd("aes256-cbc"), setup_rsa, teardown) \ + f(client, rsa_aes256_ctr, ciphercmd("aes256-ctr"), setup_rsa, teardown) \ + f(client, rsa_blowfish_cbc, ciphercmd("blowfish-cbc"), setup_rsa, teardown) \ + f(client, ecdsa_256_3des_cbc, ciphercmd("3des-cbc"), setup_ecdsa_256, teardown) \ + f(client, ecdsa_256_aes128_cbc, ciphercmd("aes128-cbc"), setup_ecdsa_256, teardown) \ + f(client, ecdsa_256_aes128_ctr, ciphercmd("aes128-ctr"), setup_ecdsa_256, teardown) \ + f(client, ecdsa_256_aes256_cbc, ciphercmd("aes256-cbc"), setup_ecdsa_256, teardown) \ + f(client, ecdsa_256_aes256_ctr, ciphercmd("aes256-ctr"), setup_ecdsa_256, teardown) \ + f(client, ecdsa_256_blowfish_cbc, ciphercmd("blowfish-cbc"), setup_ecdsa_256, teardown) \ + f(client, ecdsa_384_3des_cbc, ciphercmd("3des-cbc"), setup_ecdsa_384, teardown) \ + f(client, ecdsa_384_aes128_cbc, ciphercmd("aes128-cbc"), setup_ecdsa_384, teardown) \ + f(client, ecdsa_384_aes128_ctr, ciphercmd("aes128-ctr"), setup_ecdsa_384, teardown) \ + f(client, ecdsa_384_aes256_cbc, ciphercmd("aes256-cbc"), setup_ecdsa_384, teardown) \ + f(client, ecdsa_384_aes256_ctr, ciphercmd("aes256-ctr"), setup_ecdsa_384, teardown) \ + f(client, ecdsa_384_blowfish_cbc, ciphercmd("blowfish-cbc"), setup_ecdsa_384, teardown) \ + f(client, ecdsa_521_3des_cbc, ciphercmd("3des-cbc"), setup_ecdsa_521, teardown) \ + f(client, ecdsa_521_aes128_cbc, ciphercmd("aes128-cbc"), setup_ecdsa_521, teardown) \ + f(client, ecdsa_521_aes128_ctr, ciphercmd("aes128-ctr"), setup_ecdsa_521, teardown) \ + f(client, ecdsa_521_aes256_cbc, ciphercmd("aes256-cbc"), setup_ecdsa_521, teardown) \ + f(client, ecdsa_521_aes256_ctr, ciphercmd("aes256-ctr"), setup_ecdsa_521, teardown) \ + f(client, ecdsa_521_blowfish_cbc, ciphercmd("blowfish-cbc"), setup_ecdsa_521, teardown) +#endif +#ifdef HAVE_DSA #define PKDTESTS_CIPHER_OPENSSHONLY(f, client, ciphercmd) \ /* Ciphers. */ \ f(client, rsa_aes192_cbc, ciphercmd("aes192-cbc"), setup_rsa, teardown) \ @@ -264,7 +326,20 @@ static int torture_pkd_setup_ecdsa_521(void **state) { f(client, ecdsa_384_aes192_ctr, ciphercmd("aes192-ctr"), setup_ecdsa_384, teardown) \ f(client, ecdsa_521_aes192_cbc, ciphercmd("aes192-cbc"), setup_ecdsa_521, teardown) \ f(client, ecdsa_521_aes192_ctr, ciphercmd("aes192-ctr"), setup_ecdsa_521, teardown) +#else +#define PKDTESTS_CIPHER_OPENSSHONLY(f, client, ciphercmd) \ + /* Ciphers. */ \ + f(client, rsa_aes192_cbc, ciphercmd("aes192-cbc"), setup_rsa, teardown) \ + f(client, rsa_aes192_ctr, ciphercmd("aes192-ctr"), setup_rsa, teardown) \ + f(client, ecdsa_256_aes192_cbc, ciphercmd("aes192-cbc"), setup_ecdsa_256, teardown) \ + f(client, ecdsa_256_aes192_ctr, ciphercmd("aes192-ctr"), setup_ecdsa_256, teardown) \ + f(client, ecdsa_384_aes192_cbc, ciphercmd("aes192-cbc"), setup_ecdsa_384, teardown) \ + f(client, ecdsa_384_aes192_ctr, ciphercmd("aes192-ctr"), setup_ecdsa_384, teardown) \ + f(client, ecdsa_521_aes192_cbc, ciphercmd("aes192-cbc"), setup_ecdsa_521, teardown) \ + f(client, ecdsa_521_aes192_ctr, ciphercmd("aes192-ctr"), setup_ecdsa_521, teardown) +#endif +#ifdef HAVE_DSA #define PKDTESTS_MAC(f, client, maccmd) \ /* MACs. */ \ f(client, rsa_hmac_sha1, maccmd("hmac-sha1"), setup_rsa, teardown) \ @@ -282,6 +357,22 @@ static int torture_pkd_setup_ecdsa_521(void **state) { f(client, ecdsa_256_hmac_sha2_512, maccmd("hmac-sha2-512"), setup_ecdsa_256, teardown) \ f(client, ecdsa_384_hmac_sha2_512, maccmd("hmac-sha2-512"), setup_ecdsa_384, teardown) \ f(client, ecdsa_521_hmac_sha2_512, maccmd("hmac-sha2-512"), setup_ecdsa_521, teardown) +#else +#define PKDTESTS_MAC(f, client, maccmd) \ + /* MACs. */ \ + f(client, rsa_hmac_sha1, maccmd("hmac-sha1"), setup_rsa, teardown) \ + f(client, ecdsa_256_hmac_sha1, maccmd("hmac-sha1"), setup_ecdsa_256, teardown) \ + f(client, ecdsa_384_hmac_sha1, maccmd("hmac-sha1"), setup_ecdsa_384, teardown) \ + f(client, ecdsa_521_hmac_sha1, maccmd("hmac-sha1"), setup_ecdsa_521, teardown) \ + f(client, rsa_hmac_sha2_256, maccmd("hmac-sha2-256"), setup_rsa, teardown) \ + f(client, ecdsa_256_hmac_sha2_256, maccmd("hmac-sha2-256"), setup_ecdsa_256, teardown) \ + f(client, ecdsa_384_hmac_sha2_256, maccmd("hmac-sha2-256"), setup_ecdsa_384, teardown) \ + f(client, ecdsa_521_hmac_sha2_256, maccmd("hmac-sha2-256"), setup_ecdsa_521, teardown) \ + f(client, rsa_hmac_sha2_512, maccmd("hmac-sha2-512"), setup_rsa, teardown) \ + f(client, ecdsa_256_hmac_sha2_512, maccmd("hmac-sha2-512"), setup_ecdsa_256, teardown) \ + f(client, ecdsa_384_hmac_sha2_512, maccmd("hmac-sha2-512"), setup_ecdsa_384, teardown) \ + f(client, ecdsa_521_hmac_sha2_512, maccmd("hmac-sha2-512"), setup_ecdsa_521, teardown) +#endif static void torture_pkd_client_noop(void **state) { struct pkd_state *pstate = (struct pkd_state *) (*state); @@ -328,6 +419,7 @@ static void torture_pkd_runtest(const char *testname, * Actual test functions are emitted here. */ +#ifdef HAVE_DSA #define CLIENT_ID_FILE OPENSSH_DSA_TESTKEY PKDTESTS_DEFAULT(emit_keytest, openssh_dsa, OPENSSH_CMD) PKDTESTS_KEX(emit_keytest, openssh_dsa, OPENSSH_KEX_CMD) @@ -335,6 +427,7 @@ PKDTESTS_CIPHER(emit_keytest, openssh_dsa, OPENSSH_CIPHER_CMD) PKDTESTS_CIPHER_OPENSSHONLY(emit_keytest, openssh_dsa, OPENSSH_CIPHER_CMD) PKDTESTS_MAC(emit_keytest, openssh_dsa, OPENSSH_MAC_CMD) #undef CLIENT_ID_FILE +#endif #define CLIENT_ID_FILE OPENSSH_RSA_TESTKEY PKDTESTS_DEFAULT(emit_keytest, openssh_rsa, OPENSSH_CMD) @@ -393,11 +486,13 @@ struct { const struct CMUnitTest test; } testmap[] = { /* OpenSSH */ +#ifdef HAVE_DSA PKDTESTS_DEFAULT(emit_testmap, openssh_dsa, OPENSSH_CMD) PKDTESTS_KEX(emit_testmap, openssh_dsa, OPENSSH_KEX_CMD) PKDTESTS_CIPHER(emit_testmap, openssh_dsa, OPENSSH_CIPHER_CMD) PKDTESTS_CIPHER_OPENSSHONLY(emit_testmap, openssh_dsa, OPENSSH_CIPHER_CMD) PKDTESTS_MAC(emit_testmap, openssh_dsa, OPENSSH_MAC_CMD) +#endif PKDTESTS_DEFAULT(emit_testmap, openssh_rsa, OPENSSH_CMD) PKDTESTS_KEX(emit_testmap, openssh_rsa, OPENSSH_KEX_CMD) @@ -438,11 +533,13 @@ static int pkd_run_tests(void) { int tindex = 0; const struct CMUnitTest openssh_tests[] = { +#ifdef HAVE_DSA PKDTESTS_DEFAULT(emit_unit_test_comma, openssh_dsa, OPENSSH_CMD) PKDTESTS_KEX(emit_unit_test_comma, openssh_dsa, OPENSSH_KEX_CMD) PKDTESTS_CIPHER(emit_unit_test_comma, openssh_dsa, OPENSSH_CIPHER_CMD) PKDTESTS_CIPHER_OPENSSHONLY(emit_unit_test_comma, openssh_dsa, OPENSSH_CIPHER_CMD) PKDTESTS_MAC(emit_unit_test_comma, openssh_dsa, OPENSSH_MAC_CMD) +#endif PKDTESTS_DEFAULT(emit_unit_test_comma, openssh_rsa, OPENSSH_CMD) PKDTESTS_KEX(emit_unit_test_comma, openssh_rsa, OPENSSH_KEX_CMD) @@ -546,7 +643,9 @@ static int pkd_run_tests(void) { /* Clean up any server keys that were generated. */ cleanup_rsa_key(); +#ifdef HAVE_DSA cleanup_dsa_key(); +#endif cleanup_ecdsa_keys(); return rc; diff --git a/tests/pkd/pkd_keyutil.c b/tests/pkd/pkd_keyutil.c index e1e1ecb8..7cb2ed48 100644 --- a/tests/pkd/pkd_keyutil.c +++ b/tests/pkd/pkd_keyutil.c @@ -27,6 +27,7 @@ void setup_rsa_key() { assert_int_equal(rc, 0); } +#ifdef HAVE_DSA void setup_dsa_key() { int rc = 0; if (access(LIBSSH_DSA_TESTKEY, F_OK) != 0) { @@ -35,6 +36,7 @@ void setup_dsa_key() { } assert_int_equal(rc, 0); } +#endif void setup_ecdsa_keys() { int rc = 0; @@ -65,9 +67,11 @@ void cleanup_rsa_key() { cleanup_key(LIBSSH_RSA_TESTKEY, LIBSSH_RSA_TESTKEY ".pub"); } +#ifdef HAVE_DSA void cleanup_dsa_key() { cleanup_key(LIBSSH_DSA_TESTKEY, LIBSSH_DSA_TESTKEY ".pub"); } +#endif void cleanup_ecdsa_keys() { cleanup_key(LIBSSH_ECDSA_256_TESTKEY, LIBSSH_ECDSA_256_TESTKEY ".pub"); @@ -78,11 +82,13 @@ void cleanup_ecdsa_keys() { void setup_openssh_client_keys() { int rc = 0; +#ifdef HAVE_DSA if (access(OPENSSH_DSA_TESTKEY, F_OK) != 0) { rc = system_checked(OPENSSH_KEYGEN " -t dsa -q -N \"\" -f " OPENSSH_DSA_TESTKEY); } assert_int_equal(rc, 0); +#endif if (access(OPENSSH_RSA_TESTKEY, F_OK) != 0) { rc = system_checked(OPENSSH_KEYGEN " -t rsa -q -N \"\" -f " @@ -116,7 +122,9 @@ void setup_openssh_client_keys() { } void cleanup_openssh_client_keys() { +#ifdef HAVE_DSA cleanup_key(OPENSSH_DSA_TESTKEY, OPENSSH_DSA_TESTKEY ".pub"); +#endif cleanup_key(OPENSSH_RSA_TESTKEY, OPENSSH_RSA_TESTKEY ".pub"); cleanup_key(OPENSSH_ECDSA256_TESTKEY, OPENSSH_ECDSA256_TESTKEY ".pub"); cleanup_key(OPENSSH_ECDSA384_TESTKEY, OPENSSH_ECDSA384_TESTKEY ".pub"); diff --git a/tests/pkd/pkd_keyutil.h b/tests/pkd/pkd_keyutil.h index 8e9de009..3d0ae5a7 100644 --- a/tests/pkd/pkd_keyutil.h +++ b/tests/pkd/pkd_keyutil.h @@ -7,22 +7,32 @@ #ifndef __PKD_KEYUTIL_H__ #define __PKD_KEYUTIL_H__ +#include "config.h" + /* Server keys. */ +#ifdef HAVE_DSA #define LIBSSH_DSA_TESTKEY "libssh_testkey.id_dsa" +#endif #define LIBSSH_RSA_TESTKEY "libssh_testkey.id_rsa" #define LIBSSH_ECDSA_256_TESTKEY "libssh_testkey.id_ecdsa256" #define LIBSSH_ECDSA_384_TESTKEY "libssh_testkey.id_ecdsa384" #define LIBSSH_ECDSA_521_TESTKEY "libssh_testkey.id_ecdsa521" +#ifdef HAVE_DSA void setup_dsa_key(void); +#endif void setup_rsa_key(void); void setup_ecdsa_keys(void); +#ifdef HAVE_DSA void cleanup_dsa_key(void); +#endif void cleanup_rsa_key(void); void cleanup_ecdsa_keys(void); /* Client keys. */ +#ifdef HAVE_DSA #define OPENSSH_DSA_TESTKEY "openssh_testkey.id_dsa" +#endif #define OPENSSH_RSA_TESTKEY "openssh_testkey.id_rsa" #define OPENSSH_ECDSA256_TESTKEY "openssh_testkey.id_ecdsa256" #define OPENSSH_ECDSA384_TESTKEY "openssh_testkey.id_ecdsa384" diff --git a/tests/test_ssh_bind_accept_fd.c b/tests/test_ssh_bind_accept_fd.c index 7611cf4c..5aa8211a 100644 --- a/tests/test_ssh_bind_accept_fd.c +++ b/tests/test_ssh_bind_accept_fd.c @@ -73,10 +73,18 @@ void ssh_server() { errx(1, "ssh_bind_new"); } +#ifdef HAVE_DSA + /*TODO mbedtls this is probably required */ if (ssh_bind_options_set(bind, SSH_BIND_OPTIONS_DSAKEY, options.server_keyfile) != SSH_OK) { errx(1, "ssh_bind_options_set(SSH_BIND_OPTIONS_DSAKEY"); } +#else + if (ssh_bind_options_set(bind, SSH_BIND_OPTIONS_RSAKEY, + options.server_keyfile) != SSH_OK) { + errx(1, "ssh_bind_options_set(SSH_BIND_OPTIONS_RSAKEY"); + } +#endif session = ssh_new(); if (!session) { diff --git a/tests/torture.c b/tests/torture.c index 8486eb41..26f15ce0 100644 --- a/tests/torture.c +++ b/tests/torture.c @@ -113,6 +113,7 @@ static const char torture_rsa_testkey_cert[] = "neB6OdgTpKFsmgPZVtqrvhjw+b5T8a4W4iWSl+6wg6gowAm " "rsa_privkey.pub\n"; +#ifdef HAVE_DSA static const char torture_dsa_testkey[] = "-----BEGIN DSA PRIVATE KEY-----\n" "MIIBuwIBAAKBgQCUyvVPEkn3UnZDjzCzSzSHpTltzr0Ec+1mz/JACjHMBJ9C/W/P\n" @@ -167,6 +168,7 @@ static const char torture_dsa_testkey_cert[] = "4mMXgzaLViFtcwah6wHGlW0UPQMvrq/RqigAkyUszSccfibkIXJ+wGAgsRYhVAMwME" "JqPZ6GHOEIjLBKUegsclHb7Pk0YO8Auaw== " "aris@aris-air\n"; +#endif static const char torture_rsa_testkey_pp[] = "-----BEGIN RSA PRIVATE KEY-----\n" @@ -200,6 +202,7 @@ static const char torture_rsa_testkey_pp[] = "JSvUyxoaZUjQkT7iF94HsF+FVVJdI55UjgnMiZ0d5vKffWyTHYcYHkFYaSloAMWN\n" "-----END RSA PRIVATE KEY-----\n"; +#ifdef HAVE_DSA static const char torture_dsa_testkey_pp[] = "-----BEGIN DSA PRIVATE KEY-----\n" "Proc-Type: 4,ENCRYPTED\n" @@ -216,6 +219,7 @@ static const char torture_dsa_testkey_pp[] = "HTSuHZ7edjoWqwnl/vkc3+nG//IEj8LqAacx0i4krDcQpGuQ6BnPfwPFco2NQQpw\n" "wHBOL6HrOnD+gGs6DUFwzA==\n" "-----END DSA PRIVATE KEY-----\n"; +#endif static const char torture_ecdsa256_testkey[] = "-----BEGIN EC PRIVATE KEY-----\n" @@ -571,9 +575,11 @@ ssh_bind torture_ssh_bind(const char *addr, } switch (key_type) { +#ifdef HAVE_DSA case SSH_KEYTYPE_DSS: opts = SSH_BIND_OPTIONS_DSAKEY; break; +#endif case SSH_KEYTYPE_RSA: opts = SSH_BIND_OPTIONS_RSAKEY; break; @@ -694,6 +700,7 @@ static const char *torture_get_testkey_internal(enum ssh_keytypes_e type, int pubkey) { switch (type) { +#ifdef HAVE_DSA case SSH_KEYTYPE_DSS: if (pubkey) { return torture_dsa_testkey_pub; @@ -701,6 +708,7 @@ static const char *torture_get_testkey_internal(enum ssh_keytypes_e type, return torture_dsa_testkey_pp; } return torture_dsa_testkey; +#endif case SSH_KEYTYPE_RSA: if (pubkey) { return torture_rsa_testkey_pub; @@ -738,8 +746,10 @@ static const char *torture_get_testkey_internal(enum ssh_keytypes_e type, return torture_ed25519_testkey_pp; } return torture_ed25519_testkey; +#ifdef HAVE_DSA case SSH_KEYTYPE_DSS_CERT01: return torture_dsa_testkey_cert; +#endif case SSH_KEYTYPE_RSA_CERT01: return torture_rsa_testkey_cert; case SSH_KEYTYPE_RSA1: @@ -862,7 +872,9 @@ void torture_setup_socket_dir(void **state) static void torture_setup_create_sshd_config(void **state) { struct torture_state *s = *state; +#ifdef HAVE_DSA char dsa_hostkey[1024]; +#endif char rsa_hostkey[1024]; char ecdsa_hostkey[1024]; char trusted_ca_pubkey[1024]; @@ -882,7 +894,9 @@ static void torture_setup_create_sshd_config(void **state) const char config_string[]= "Port 22\n" "ListenAddress 127.0.0.10\n" +#ifdef HAVE_DSA "HostKey %s\n" +#endif "HostKey %s\n" "HostKey %s\n" "\n" @@ -901,8 +915,12 @@ static void torture_setup_create_sshd_config(void **state) "UsePAM yes\n" "\n" #if (OPENSSH_VERSION_MAJOR == 6 && OPENSSH_VERSION_MINOR >= 7) || (OPENSSH_VERSION_MAJOR >= 7) +# ifdef HAVE_DSA "HostKeyAlgorithms +ssh-dss\n" -# if (OPENSSH_VERSION_MAJOR == 7 && OPENSSH_VERSION_MINOR < 6) +# else + "HostKeyAlgorithms +ssh-rsa\n" +# endif +# if (OPENSSH_VERSION_MAJOR == 7 && OPENSSH_VERSION_MINOR < 6) "Ciphers +3des-cbc,aes128-cbc,aes192-cbc,aes256-cbc,blowfish-cbc\n" # else "Ciphers +3des-cbc,aes128-cbc,aes192-cbc,aes256-cbc\n" @@ -939,11 +957,13 @@ static void torture_setup_create_sshd_config(void **state) rc = mkdir(sshd_path, 0755); assert_return_code(rc, errno); +#ifdef HAVE_DSA snprintf(dsa_hostkey, sizeof(dsa_hostkey), "%s/sshd/ssh_host_dsa_key", s->socket_dir); torture_write_file(dsa_hostkey, torture_get_testkey(SSH_KEYTYPE_DSS, 0, 0)); +#endif snprintf(rsa_hostkey, sizeof(rsa_hostkey), @@ -980,7 +1000,9 @@ static void torture_setup_create_sshd_config(void **state) snprintf(sshd_config, sizeof(sshd_config), config_string, +#ifdef HAVE_DSA dsa_hostkey, +#endif rsa_hostkey, ecdsa_hostkey, trusted_ca_pubkey, diff --git a/tests/unittests/torture_keyfiles.c b/tests/unittests/torture_keyfiles.c index 023396e7..ea456050 100644 --- a/tests/unittests/torture_keyfiles.c +++ b/tests/unittests/torture_keyfiles.c @@ -6,7 +6,9 @@ #include "legacy.c" #define LIBSSH_RSA_TESTKEY "libssh_testkey.id_rsa" +#ifdef HAVE_DSA #define LIBSSH_DSA_TESTKEY "libssh_testkey.id_dsa" +#endif static int setup_rsa_key(void **state) { @@ -26,6 +28,7 @@ static int setup_rsa_key(void **state) return 0; } +#ifdef HAVE_DSA static int setup_dsa_key(void **state) { ssh_session session; @@ -43,6 +46,7 @@ static int setup_dsa_key(void **state) return 0; } +#endif static int setup_both_keys(void **state) { int rc; @@ -51,9 +55,11 @@ static int setup_both_keys(void **state) { if (rc != 0) { return rc; } +#ifdef HAVE_DSA ssh_free(*state); rc = setup_dsa_key(state); +#endif return rc; } @@ -67,10 +73,12 @@ static int setup_both_keys_passphrase(void **state) torture_write_file(LIBSSH_RSA_TESTKEY ".pub", torture_get_testkey_pub(SSH_KEYTYPE_RSA, 0)); +#ifdef HAVE_DSA torture_write_file(LIBSSH_DSA_TESTKEY, torture_get_testkey(SSH_KEYTYPE_DSS, 0, 1)); torture_write_file(LIBSSH_DSA_TESTKEY ".pub", torture_get_testkey_pub(SSH_KEYTYPE_DSS, 0)); +#endif session = ssh_new(); *state = session; @@ -80,8 +88,10 @@ static int setup_both_keys_passphrase(void **state) static int teardown(void **state) { +#ifdef HAVE_DSA unlink(LIBSSH_DSA_TESTKEY); unlink(LIBSSH_DSA_TESTKEY ".pub"); +#endif unlink(LIBSSH_RSA_TESTKEY); unlink(LIBSSH_RSA_TESTKEY ".pub"); @@ -216,12 +226,14 @@ static void torture_privatekey_from_file(void **state) { key = NULL; } +#ifdef HAVE_DSA key = privatekey_from_file(session, LIBSSH_DSA_TESTKEY, SSH_KEYTYPE_DSS, NULL); assert_true(key != NULL); if (key != NULL) { privatekey_free(key); key = NULL; } +#endif /* Test the automatic type discovery */ key = privatekey_from_file(session, LIBSSH_RSA_TESTKEY, 0, NULL); @@ -231,12 +243,14 @@ static void torture_privatekey_from_file(void **state) { key = NULL; } +#ifdef HAVE_DSA key = privatekey_from_file(session, LIBSSH_DSA_TESTKEY, 0, NULL); assert_true(key != NULL); if (key != NULL) { privatekey_free(key); key = NULL; } +#endif } /** @@ -253,12 +267,14 @@ static void torture_privatekey_from_file_passphrase(void **state) { key = NULL; } +#ifdef HAVE_DSA key = privatekey_from_file(session, LIBSSH_DSA_TESTKEY, SSH_KEYTYPE_DSS, TORTURE_TESTKEY_PASSWORD); assert_true(key != NULL); if (key != NULL) { privatekey_free(key); key = NULL; } +#endif /* Test the automatic type discovery */ key = privatekey_from_file(session, LIBSSH_RSA_TESTKEY, 0, TORTURE_TESTKEY_PASSWORD); @@ -268,12 +284,14 @@ static void torture_privatekey_from_file_passphrase(void **state) { key = NULL; } +#ifdef HAVE_DSA key = privatekey_from_file(session, LIBSSH_DSA_TESTKEY, 0, TORTURE_TESTKEY_PASSWORD); assert_true(key != NULL); if (key != NULL) { privatekey_free(key); key = NULL; } +#endif } int torture_run_tests(void) { diff --git a/tests/unittests/torture_options.c b/tests/unittests/torture_options.c index 66348147..0203ab67 100644 --- a/tests/unittests/torture_options.c +++ b/tests/unittests/torture_options.c @@ -366,11 +366,13 @@ static void torture_bind_options_import_key(void **state) ssh_pki_import_privkey_base64(base64_key, NULL, NULL, NULL, &key); rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_IMPORT_KEY, key); assert_int_equal(rc, 0); +#ifdef HAVE_DSA /* set dsa key */ base64_key = torture_get_testkey(SSH_KEYTYPE_DSS, 0, 0); ssh_pki_import_privkey_base64(base64_key, NULL, NULL, NULL, &key); rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_IMPORT_KEY, key); assert_int_equal(rc, 0); +#endif /* set ecdsa key */ base64_key = torture_get_testkey(SSH_KEYTYPE_ECDSA, 512, 0); ssh_pki_import_privkey_base64(base64_key, NULL, NULL, NULL, &key); diff --git a/tests/unittests/torture_pki.c b/tests/unittests/torture_pki.c index b0e6840c..33e7cd89 100644 --- a/tests/unittests/torture_pki.c +++ b/tests/unittests/torture_pki.c @@ -8,7 +8,9 @@ #include <fcntl.h> #define LIBSSH_RSA_TESTKEY "libssh_testkey.id_rsa" +#ifdef HAVE_DSA #define LIBSSH_DSA_TESTKEY "libssh_testkey.id_dsa" +#endif #define LIBSSH_ECDSA_TESTKEY "libssh_testkey.id_ecdsa" #define LIBSSH_ED25519_TESTKEY "libssh_testkey.id_ed25519" @@ -32,6 +34,7 @@ static int setup_rsa_key(void **state) return 0; } +#ifdef HAVE_DSA static int setup_dsa_key(void **state) { (void) state; /* unused */ @@ -48,6 +51,7 @@ static int setup_dsa_key(void **state) { return 0; } +#endif #ifdef HAVE_ECC static int setup_ecdsa_key(void **state, int ecdsa_bits) { @@ -103,7 +107,9 @@ static int setup_both_keys(void **state) { (void) state; /* unused */ setup_rsa_key(state); +#ifdef HAVE_DSA setup_dsa_key(state); +#endif return 0; } @@ -111,9 +117,11 @@ static int setup_both_keys(void **state) { static int teardown(void **state) { (void) state; /* unused */ +#ifdef HAVE_DSA unlink(LIBSSH_DSA_TESTKEY); unlink(LIBSSH_DSA_TESTKEY ".pub"); unlink(LIBSSH_DSA_TESTKEY "-cert.pub"); +#endif unlink(LIBSSH_RSA_TESTKEY); unlink(LIBSSH_RSA_TESTKEY ".pub"); @@ -281,6 +289,7 @@ static void torture_pki_import_privkey_base64_NULL_str(void **state) { ssh_key_free(key); } +#ifdef HAVE_DSA static void torture_pki_import_privkey_base64_DSA(void **state) { int rc; ssh_key key; @@ -297,6 +306,7 @@ static void torture_pki_import_privkey_base64_DSA(void **state) { ssh_key_free(key); } +#endif #ifdef HAVE_ECC static void torture_pki_import_privkey_base64_ECDSA(void **state) { @@ -349,6 +359,8 @@ static void torture_pki_import_privkey_base64_passphrase(void **state) { NULL, &key); assert_true(rc == -1); + ssh_key_free(key); + key = NULL; #ifndef HAVE_LIBCRYPTO /* test if it returns -1 if passphrase is NULL */ @@ -359,7 +371,10 @@ static void torture_pki_import_privkey_base64_passphrase(void **state) { NULL, &key); assert_true(rc == -1); + ssh_key_free(key); + key = NULL; #endif +#ifdef HAVE_DSA /* same for DSA */ @@ -384,7 +399,6 @@ static void torture_pki_import_privkey_base64_passphrase(void **state) { &key); assert_true(rc == -1); -#ifndef HAVE_LIBCRYPTO /* test if it returns -1 if passphrase is NULL */ /* libcrypto asks for a passphrase, so skip this test */ rc = ssh_pki_import_privkey_base64(torture_get_testkey(SSH_KEYTYPE_DSS, 0, 1), @@ -393,10 +407,8 @@ static void torture_pki_import_privkey_base64_passphrase(void **state) { NULL, &key); assert_true(rc == -1); -#endif - +# endif /* same for ED25519 */ - rc = ssh_pki_import_privkey_base64(torture_get_testkey(SSH_KEYTYPE_ED25519, 0, 1), passphrase, NULL, @@ -417,7 +429,6 @@ static void torture_pki_import_privkey_base64_passphrase(void **state) { NULL, &key); assert_true(rc == -1); - } static void torture_pki_import_privkey_base64_ed25519(void **state){ @@ -474,6 +485,7 @@ static void torture_pki_pki_publickey_from_privatekey_RSA(void **state) { ssh_key_free(pubkey); } +#ifdef HAVE_DSA static void torture_pki_pki_publickey_from_privatekey_DSA(void **state) { int rc; ssh_key key; @@ -498,6 +510,7 @@ static void torture_pki_pki_publickey_from_privatekey_DSA(void **state) { ssh_key_free(key); ssh_key_free(pubkey); } +#endif static void torture_pki_pki_publickey_from_privatekey_ed25519(void **state){ int rc; @@ -621,6 +634,7 @@ static void torture_pki_import_cert_file_rsa(void **state) { ssh_key_free(cert); } +#ifdef HAVE_DSA static void torture_pki_import_cert_file_dsa(void **state) { int rc; ssh_key cert; @@ -676,6 +690,7 @@ static void torture_pki_publickey_dsa_base64(void **state) free(key_buf); ssh_key_free(key); } +#endif #ifdef HAVE_ECC static void torture_pki_publickey_ecdsa_base64(void **state) @@ -829,6 +844,7 @@ static void torture_generate_pubkey_from_privkey_rsa(void **state) { ssh_key_free(pubkey); } +#ifdef HAVE_DSA static void torture_generate_pubkey_from_privkey_dsa(void **state) { char pubkey_generated[4096] = {0}; ssh_key privkey; @@ -867,6 +883,7 @@ static void torture_generate_pubkey_from_privkey_dsa(void **state) { ssh_key_free(privkey); ssh_key_free(pubkey); } +#endif static void torture_generate_pubkey_from_privkey_ed25519(void **state){ char pubkey_generated[4096] = {0}; @@ -997,6 +1014,7 @@ static void torture_pki_duplicate_key_rsa(void **state) ssh_string_free_char(b64_key_gen); } +#ifdef HAVE_DSA static void torture_pki_duplicate_key_dsa(void **state) { int rc; @@ -1042,6 +1060,7 @@ static void torture_pki_duplicate_key_dsa(void **state) ssh_string_free_char(b64_key); ssh_string_free_char(b64_key_gen); } +#endif #ifdef HAVE_ECC static void torture_pki_duplicate_key_ecdsa(void **state) @@ -1080,8 +1099,11 @@ static void torture_pki_duplicate_key_ecdsa(void **state) assert_string_equal(b64_key, b64_key_gen); +#ifndef HAVE_LIBMBEDCRYPTO + /* libmbedcrypto can't compare ecdsa keys */ rc = ssh_key_cmp(privkey, privkey_dup, SSH_KEY_CMP_PRIVATE); assert_true(rc == 0); +#endif ssh_key_free(pubkey); ssh_key_free(privkey); @@ -1212,6 +1234,7 @@ static void torture_pki_generate_key_rsa1(void **state) ssh_free(session); } +#ifdef HAVE_DSA static void torture_pki_generate_key_dsa(void **state) { int rc; @@ -1255,6 +1278,7 @@ static void torture_pki_generate_key_dsa(void **state) ssh_free(session); } +#endif #ifdef HAVE_ECC static void torture_pki_generate_key_ecdsa(void **state) @@ -1478,6 +1502,8 @@ static void torture_pki_write_privkey_ecdsa(void **state) #endif #endif /* HAVE_LIBCRYPTO */ +#ifdef HAVE_DSA +/* TODO mbedtls check if rsa can be used instead of dsa */ static void torture_pki_write_privkey_ed25519(void **state){ ssh_key origkey; ssh_key privkey; @@ -1543,6 +1569,7 @@ static void torture_pki_write_privkey_ed25519(void **state){ ssh_key_free(origkey); ssh_key_free(privkey); } +#endif #ifdef HAVE_ECC static void torture_pki_ecdsa_name(void **state, const char *expected_name) @@ -1595,9 +1622,11 @@ int torture_run_tests(void) { cmocka_unit_test_setup_teardown(torture_pki_import_privkey_base64_RSA, setup_rsa_key, teardown), +#ifdef HAVE_DSA cmocka_unit_test_setup_teardown(torture_pki_import_privkey_base64_DSA, setup_dsa_key, teardown), +#endif #ifdef HAVE_ECC cmocka_unit_test_setup_teardown(torture_pki_import_privkey_base64_ECDSA, setup_ecdsa_key_256, @@ -1617,9 +1646,11 @@ int torture_run_tests(void) { cmocka_unit_test_setup_teardown(torture_pki_pki_publickey_from_privatekey_RSA, setup_rsa_key, teardown), +#ifdef HAVE_DSA cmocka_unit_test_setup_teardown(torture_pki_pki_publickey_from_privatekey_DSA, setup_dsa_key, teardown), +#endif #ifdef HAVE_ECC cmocka_unit_test_setup_teardown(torture_pki_publickey_from_privatekey_ECDSA, setup_ecdsa_key_256, @@ -1650,6 +1681,7 @@ int torture_run_tests(void) { cmocka_unit_test_setup_teardown(torture_pki_import_cert_file_rsa, setup_rsa_key, teardown), +#ifdef HAVE_DSA cmocka_unit_test_setup_teardown(torture_pki_import_cert_file_dsa, setup_dsa_key, teardown), @@ -1658,6 +1690,7 @@ int torture_run_tests(void) { cmocka_unit_test_setup_teardown(torture_pki_publickey_dsa_base64, setup_dsa_key, teardown), +#endif cmocka_unit_test_setup_teardown(torture_pki_publickey_rsa_base64, setup_rsa_key, teardown), @@ -1675,9 +1708,11 @@ int torture_run_tests(void) { cmocka_unit_test_setup_teardown(torture_pki_publickey_ed25519_base64, setup_ed25519_key, teardown), +#ifdef HAVE_DSA cmocka_unit_test_setup_teardown(torture_generate_pubkey_from_privkey_dsa, setup_dsa_key, teardown), +#endif cmocka_unit_test_setup_teardown(torture_generate_pubkey_from_privkey_rsa, setup_rsa_key, teardown), @@ -1698,9 +1733,11 @@ int torture_run_tests(void) { cmocka_unit_test_setup_teardown(torture_pki_duplicate_key_rsa, setup_rsa_key, teardown), +#ifdef HAVE_DSA cmocka_unit_test_setup_teardown(torture_pki_duplicate_key_dsa, setup_dsa_key, teardown), +#endif #ifdef HAVE_ECC cmocka_unit_test_setup_teardown(torture_pki_duplicate_key_ecdsa, setup_ecdsa_key_256, @@ -1712,12 +1749,16 @@ int torture_run_tests(void) { setup_ecdsa_key_521, teardown), #endif +#ifdef HAVE_DSA cmocka_unit_test_setup_teardown(torture_pki_duplicate_key_dsa, setup_dsa_key, teardown), +#endif cmocka_unit_test(torture_pki_generate_key_rsa), cmocka_unit_test(torture_pki_generate_key_rsa1), +#ifdef HAVE_DSA cmocka_unit_test(torture_pki_generate_key_dsa), +#endif #ifdef HAVE_ECC cmocka_unit_test(torture_pki_generate_key_ecdsa), #endif @@ -1741,9 +1782,11 @@ int torture_run_tests(void) { teardown), #endif #endif /* HAVE_LIBCRYPTO */ +#ifdef HAVE_DSA cmocka_unit_test_setup_teardown(torture_pki_write_privkey_ed25519, setup_dsa_key, teardown), +#endif #ifdef HAVE_ECC cmocka_unit_test_setup_teardown(torture_pki_ecdsa_name256, |