mirror of
https://git.libssh.org/projects/libssh.git
synced 2026-02-05 21:00:33 +09:00
Compare commits
22 Commits
34db488e4d
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
76b14eaed7 | ||
|
|
8e8f091aba | ||
|
|
d75a54e206 | ||
|
|
efb7a7c4e0 | ||
|
|
7342e73d10 | ||
|
|
832f92e35f | ||
|
|
ea3464532e | ||
|
|
7e235f8748 | ||
|
|
052c8217b7 | ||
|
|
26b9ba5f8c | ||
|
|
1b3c061aae | ||
|
|
1525ea3dda | ||
|
|
a189c2ef4d | ||
|
|
b2abcf8534 | ||
|
|
809f9b7729 | ||
|
|
d297621c33 | ||
|
|
d936b7e81d | ||
|
|
971d44107e | ||
|
|
a1e49728ba | ||
|
|
6c5459e7fc | ||
|
|
f47d1c797a | ||
|
|
da27d23125 |
@@ -301,6 +301,37 @@ fedora/openssl_3.x/x86_64/minimal:
|
||||
make test_memcheck
|
||||
- cat Testing/Temporary/MemoryChecker.*.log | wc -l | grep "^0$"
|
||||
|
||||
fedora/libressl/x86_64:
|
||||
extends: .fedora
|
||||
stage: test
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
|
||||
variables:
|
||||
LIBRESSL_VERSION: "4.2.1"
|
||||
CMAKE_ADDITIONAL_OPTIONS: >
|
||||
-DCMAKE_C_FLAGS="-I/opt/libressl/include"
|
||||
-DOPENSSL_ROOT_DIR=/opt/libressl
|
||||
-DOPENSSL_INCLUDE_DIR=/opt/libressl/include
|
||||
-DOPENSSL_CRYPTO_LIBRARY=/opt/libressl/lib/libcrypto.so
|
||||
-DOPENSSL_SSL_LIBRARY=/opt/libressl/lib/libssl.so
|
||||
-DWITH_GSSAPI=OFF
|
||||
-DWITH_FIDO2=OFF
|
||||
before_script:
|
||||
- *build
|
||||
- dnf install -y perl-core autoconf automake libtool pkgconf-pkg-config
|
||||
- curl -LO https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-${LIBRESSL_VERSION}.tar.gz
|
||||
- tar xf libressl-${LIBRESSL_VERSION}.tar.gz
|
||||
- cd libressl-${LIBRESSL_VERSION}
|
||||
- ./configure --prefix=/opt/libressl
|
||||
- make -j$(nproc)
|
||||
- make install
|
||||
- cd ..
|
||||
script:
|
||||
- export PKG_CONFIG_PATH=/opt/libressl/lib/pkgconfig
|
||||
- export LD_LIBRARY_PATH=/opt/libressl/lib
|
||||
- cmake $CMAKE_OPTIONS $CMAKE_ADDITIONAL_OPTIONS .. &&
|
||||
make -j$(nproc) &&
|
||||
ctest --output-on-failure
|
||||
|
||||
# The PKCS#11 support is turned off as it brings dozens of memory issues from
|
||||
# engine_pkcs11 or openssl itself
|
||||
fedora/valgrind/openssl:
|
||||
|
||||
116
.gitlab-ci/local-ci.sh
Executable file
116
.gitlab-ci/local-ci.sh
Executable file
@@ -0,0 +1,116 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
RED="\033[1;31m"
|
||||
GREEN="\033[1;32m"
|
||||
YELLOW="\033[1;33m"
|
||||
BLUE="\033[1;34m"
|
||||
RESET="\033[0m"
|
||||
|
||||
export GCL_IGNORE_PREDEFINED_VARS=CI_REGISTRY
|
||||
|
||||
BASE_SHA=$(git merge-base HEAD origin/master 2>/dev/null || git rev-parse HEAD~1)
|
||||
|
||||
COMMON_ARGS=(
|
||||
--variable "CI_MERGE_REQUEST_DIFF_BASE_SHA=$BASE_SHA"
|
||||
--variable "CI_REGISTRY=registry.gitlab.com"
|
||||
--json-schema-validation=false
|
||||
)
|
||||
|
||||
check_requirements() {
|
||||
for cmd in docker git gitlab-ci-local; do
|
||||
if ! command -v "$cmd" >/dev/null 2>&1; then
|
||||
echo -e "${RED}Missing dependency: $cmd${RESET}"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}Found: $cmd${RESET}"
|
||||
done
|
||||
|
||||
if ! docker info >/dev/null 2>&1; then
|
||||
echo -e "${RED}Docker daemon is not running or permission denied${RESET}"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
list_jobs() {
|
||||
gitlab-ci-local --list --json-schema-validation=false | awk 'NR>1 {print $1}'
|
||||
}
|
||||
|
||||
run_job() {
|
||||
JOB="$1"
|
||||
echo -e "${YELLOW}Running CI job: $JOB${RESET}"
|
||||
gitlab-ci-local "$JOB" "${COMMON_ARGS[@]}"
|
||||
}
|
||||
|
||||
cleanup_images() {
|
||||
echo -e "${BLUE}Removing libssh CI images only...${RESET}"
|
||||
docker images --format "{{.Repository}}:{{.Tag}} {{.ID}}" \
|
||||
| grep "$CI_REGISTRY/$BUILD_IMAGES_PROJECT" \
|
||||
| awk '{print $2}' \
|
||||
| xargs -r docker rmi -f
|
||||
}
|
||||
|
||||
usage() {
|
||||
echo
|
||||
echo -e "${BLUE}Usage:${RESET}"
|
||||
echo " $0 --list"
|
||||
echo " $0 --run <job-name>"
|
||||
echo " $0 --all"
|
||||
echo " $0 --run <job-name> --clean"
|
||||
echo " $0 --all --clean"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
check_requirements
|
||||
|
||||
CLEAN=0
|
||||
MODE=""
|
||||
JOB=""
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--list)
|
||||
MODE="list"
|
||||
shift
|
||||
;;
|
||||
--run)
|
||||
MODE="run"
|
||||
JOB="$2"
|
||||
shift 2
|
||||
;;
|
||||
--all)
|
||||
MODE="all"
|
||||
shift
|
||||
;;
|
||||
--clean)
|
||||
CLEAN=1
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
case "$MODE" in
|
||||
list)
|
||||
list_jobs
|
||||
;;
|
||||
run)
|
||||
[[ -z "$JOB" ]] && usage
|
||||
run_job "$JOB"
|
||||
[[ "$CLEAN" -eq 1 ]] && cleanup_images
|
||||
;;
|
||||
all)
|
||||
for job in $(list_jobs); do
|
||||
run_job "$job"
|
||||
[[ "$CLEAN" -eq 1 ]] && cleanup_images
|
||||
done
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
|
||||
echo -e "${GREEN}Done.${RESET}"
|
||||
@@ -90,7 +90,7 @@ endif (WITH_FIDO2)
|
||||
|
||||
# Disable symbol versioning in non UNIX platforms
|
||||
if (UNIX)
|
||||
find_package(ABIMap 0.3.1)
|
||||
find_package(ABIMap 0.4.0)
|
||||
else (UNIX)
|
||||
set(WITH_SYMBOL_VERSIONING OFF)
|
||||
endif (UNIX)
|
||||
@@ -181,6 +181,10 @@ if (WITH_SYMBOL_VERSIONING AND ABIMAP_FOUND)
|
||||
set(ALLOW_ABI_BREAK "BREAK_ABI")
|
||||
endif()
|
||||
|
||||
if (WITH_FINAL)
|
||||
set(FINAL "FINAL")
|
||||
endif()
|
||||
|
||||
# Target we can depend on in 'make dist'
|
||||
set(_SYMBOL_TARGET "${PROJECT_NAME}.map")
|
||||
|
||||
@@ -193,7 +197,7 @@ if (WITH_SYMBOL_VERSIONING AND ABIMAP_FOUND)
|
||||
RELEASE_NAME_VERSION ${PROJECT_NAME}_${LIBRARY_VERSION}
|
||||
CURRENT_MAP ${MAP_PATH}
|
||||
COPY_TO ${MAP_PATH}
|
||||
FINAL
|
||||
${FINAL}
|
||||
${ALLOW_ABI_BREAK})
|
||||
|
||||
# Write the current version to the source
|
||||
|
||||
@@ -137,6 +137,33 @@ The script exceeded the maximum execution time set for the job
|
||||
Note, that the built dependencies are cached so after successful build in your
|
||||
namespace, the rebuilds should be much faster.
|
||||
|
||||
## Running GitLab CI locally (optional helper)
|
||||
|
||||
For contributors working on CI, build system changes, or adding new CI jobs, it can be useful to run GitLab CI pipelines locally before pushing.
|
||||
|
||||
libssh provides a small helper script based on `gitlab-ci-local` that can:
|
||||
|
||||
- List all jobs defined in `.gitlab-ci.yml`
|
||||
- Run a specific job or the full pipeline locally
|
||||
- Automatically pick up new jobs when they are added to the CI configuration
|
||||
- Optionally clean up CI Docker images after execution
|
||||
|
||||
### Requirements
|
||||
|
||||
- Docker (daemon running)
|
||||
- git
|
||||
- gitlab-ci-local
|
||||
https://github.com/firecow/gitlab-ci-local
|
||||
|
||||
### Usage
|
||||
|
||||
```bash
|
||||
./.gitlab-ci/local-ci.sh --list
|
||||
./.gitlab-ci/local-ci.sh --run fedora/libressl/x86_64
|
||||
./.gitlab-ci/local-ci.sh --all
|
||||
./.gitlab-ci/local-ci.sh --run fedora/libressl/x86_64 --clean
|
||||
```
|
||||
|
||||
# Coding conventions in the libssh tree
|
||||
|
||||
## Quick Start
|
||||
|
||||
@@ -189,7 +189,6 @@ if (DOXYGEN_FOUND)
|
||||
sftp_message,
|
||||
sftp_packet,
|
||||
sftp_request_queue,
|
||||
sftp_session,
|
||||
sftp_status_message,
|
||||
sftp_statvfs_t,
|
||||
poll_fn,
|
||||
|
||||
@@ -171,21 +171,15 @@ The following RFC documents described SSH-2 protocol as an Internet standard.
|
||||
The Secure Shell (SSH) Session Channel Break Extension
|
||||
- <a href="https://tools.ietf.org/html/rfc4344" target="_blank">RFC 4344</a>,
|
||||
The Secure Shell (SSH) Transport Layer Encryption Modes
|
||||
- <a href="https://tools.ietf.org/html/rfc4345" target="_blank">RFC 4345</a>,
|
||||
Improved Arcfour Modes for the Secure Shell (SSH) Transport Layer Protocol
|
||||
|
||||
It was later modified and expanded by the following RFCs.
|
||||
|
||||
- <a href="https://tools.ietf.org/html/rfc4419" target="_blank">RFC 4419</a>,
|
||||
Diffie-Hellman Group Exchange for the Secure Shell (SSH) Transport Layer
|
||||
Protocol
|
||||
- <a href="https://tools.ietf.org/html/rfc4432" target="_blank">RFC 4432</a>,
|
||||
RSA Key Exchange for the Secure Shell (SSH) Transport Layer Protocol
|
||||
(not implemented in libssh)
|
||||
- <a href="https://tools.ietf.org/html/rfc4462" target="_blank">RFC 4462</a>,
|
||||
Generic Security Service Application Program Interface (GSS-API)
|
||||
Authentication and Key Exchange for the Secure Shell (SSH) Protocol
|
||||
(only the authentication implemented in libssh)
|
||||
- <a href="https://tools.ietf.org/html/rfc4716" target="_blank">RFC 4716</a>,
|
||||
The Secure Shell (SSH) Public Key File Format
|
||||
(not implemented in libssh)
|
||||
@@ -204,7 +198,6 @@ It was later modified and expanded by the following RFCs.
|
||||
(not implemented in libssh)
|
||||
- <a href="https://tools.ietf.org/html/rfc8160" target="_blank">RFC 8160</a>,
|
||||
IUTF8 Terminal Mode in Secure Shell (SSH)
|
||||
(not handled in libssh)
|
||||
- <a href="https://tools.ietf.org/html/rfc8270" target="_blank">RFC 8270</a>,
|
||||
Increase the Secure Shell Minimum Recommended Diffie-Hellman Modulus Size to 2048 Bits
|
||||
- <a href="https://tools.ietf.org/html/rfc8308" target="_blank">RFC 8308</a>,
|
||||
@@ -223,6 +216,14 @@ There are also drafts that are being currently developed and followed.
|
||||
|
||||
- <a href="https://tools.ietf.org/html/draft-miller-ssh-agent-03" target="_blank">draft-miller-ssh-agent-08</a>
|
||||
SSH Agent Protocol
|
||||
- <a href="https://tools.ietf.org/html/draft-ietf-sshm-mlkem-hybrid-kex-09" target="_blank">draft-ietf-sshm-mlkem-hybrid-kex-09</a>
|
||||
PQ/T Hybrid Key Exchange with ML-KEM in SSH
|
||||
- <a href="https://tools.ietf.org/html/draft-ietf-sshm-ntruprime-ssh-06" target="_blank">draft-ietf-sshm-ntruprime-ssh-06</a>
|
||||
Secure Shell (SSH) Key Exchange Method Using Hybrid Streamlined NTRU Prime sntrup761 and X25519 with SHA-512: sntrup761x25519-sha512
|
||||
- <a href="https://tools.ietf.org/html/draft-ietf-sshm-chacha20-poly1305-02" target="_blank">draft-ietf-sshm-chacha20-poly1305-02</a>
|
||||
Secure Shell (SSH) authenticated encryption cipher: chacha20-poly1305
|
||||
- <a href="https://tools.ietf.org/html/draft-ietf-sshm-strict-kex-01" target="_blank">draft-ietf-sshm-strict-kex-01</a>
|
||||
SSH Strict KEX extension
|
||||
|
||||
Interesting cryptography documents:
|
||||
|
||||
@@ -247,8 +248,6 @@ them like the statvfs calls in SFTP or the ssh-agent.
|
||||
OpenSSH's deviations and extensions</a>
|
||||
- <a href="https://api.libssh.org/rfc/PROTOCOL.certkeys" target="_blank">
|
||||
OpenSSH's pubkey certificate authentication</a>
|
||||
- <a href="https://api.libssh.org/rfc/PROTOCOL.chacha20poly1305" target="_blank">
|
||||
chacha20-poly1305@openssh.com authenticated encryption mode</a>
|
||||
- <a href="https://api.libssh.org/rfc/PROTOCOL.key" target="_blank">
|
||||
OpenSSH private key format (openssh-key-v1)</a>
|
||||
|
||||
|
||||
@@ -74,6 +74,21 @@ typedef struct sftp_file_struct* sftp_file;
|
||||
typedef struct sftp_message_struct* sftp_message;
|
||||
typedef struct sftp_packet_struct* sftp_packet;
|
||||
typedef struct sftp_request_queue_struct* sftp_request_queue;
|
||||
|
||||
/**
|
||||
* @brief SFTP session handle.
|
||||
*
|
||||
* This type represents an active SFTP session associated with an SSH channel.
|
||||
* It is created and destroyed via the libssh SFTP API and is internally
|
||||
* managed by libssh. It is used by applications to perform SFTP operations
|
||||
* such as file access and directory management.
|
||||
*
|
||||
* The internal structure of this type is opaque and must not be accessed
|
||||
* directly by applications.
|
||||
*
|
||||
* @see sftp_new
|
||||
* @see sftp_free
|
||||
*/
|
||||
typedef struct sftp_session_struct* sftp_session;
|
||||
typedef struct sftp_status_message_struct* sftp_status_message;
|
||||
typedef struct sftp_statvfs_struct* sftp_statvfs_t;
|
||||
|
||||
@@ -1396,6 +1396,11 @@ int ssh_userauth_publickey_auto(ssh_session session,
|
||||
if (session == NULL) {
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_INFO,
|
||||
"Starting authentication as a user %s",
|
||||
username ? username : session->opts.username);
|
||||
|
||||
if (! (session->opts.flags & SSH_OPT_FLAG_PUBKEY_AUTH)) {
|
||||
session->auth.supported_methods &= ~SSH_AUTH_METHOD_PUBLICKEY;
|
||||
return SSH_AUTH_DENIED;
|
||||
|
||||
@@ -542,16 +542,8 @@ static int ssh_connector_channel_data_cb(ssh_session session,
|
||||
window_len = MIN(window, len);
|
||||
|
||||
/* Route the data to the right exception channel */
|
||||
if (is_stderr && (connector->out_flags & SSH_CONNECTOR_STDERR)) {
|
||||
w = ssh_channel_write_stderr(connector->out_channel,
|
||||
data,
|
||||
window_len);
|
||||
} else if (!is_stderr &&
|
||||
(connector->out_flags & SSH_CONNECTOR_STDOUT)) {
|
||||
w = ssh_channel_write(connector->out_channel,
|
||||
data,
|
||||
window_len);
|
||||
} else if (connector->out_flags & SSH_CONNECTOR_STDOUT) {
|
||||
if (connector->out_flags & SSH_CONNECTOR_STDOUT &&
|
||||
!(is_stderr && (connector->out_flags & SSH_CONNECTOR_STDERR))) {
|
||||
w = ssh_channel_write(connector->out_channel,
|
||||
data,
|
||||
window_len);
|
||||
|
||||
5
src/external/libcrux_mlkem768_sha3.c
vendored
5
src/external/libcrux_mlkem768_sha3.c
vendored
@@ -28,8 +28,9 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "libssh/mlkem_native.h"
|
||||
#include "libssh/priv.h"
|
||||
|
||||
#if !defined(__GNUC__) || (__GNUC__ < 2)
|
||||
# define __attribute__(x)
|
||||
@@ -38,7 +39,7 @@
|
||||
#define KRML_NOINLINE __attribute__((noinline, unused))
|
||||
#define KRML_HOST_EPRINTF(...)
|
||||
#define KRML_HOST_EXIT(x) do { \
|
||||
SSH_LOG(SSH_LOG_WARNING, "internal error"); \
|
||||
fprintf(stderr, "mlkem internal error"); \
|
||||
exit(x); \
|
||||
} while (0)
|
||||
|
||||
|
||||
@@ -850,6 +850,10 @@ int ssh_gssapi_client_identity(ssh_session session, gss_OID_set *valid_oids)
|
||||
char *ptr = NULL;
|
||||
int ret;
|
||||
|
||||
if (session == NULL || session->gssapi == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (session->gssapi->client.client_deleg_creds == NULL) {
|
||||
if (session->opts.gss_client_identity != NULL) {
|
||||
namebuf.value = (void *)session->opts.gss_client_identity;
|
||||
|
||||
@@ -216,11 +216,22 @@ ssh_known_hosts_entries_compare(struct ssh_knownhosts_entry *k1,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This method reads the known_hosts file referenced by the path
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Read entries from filename to provided list
|
||||
*
|
||||
* This method reads the known_hosts file referenced by the path
|
||||
* in filename argument, and entries matching the match argument
|
||||
* will be added to the list in entries argument.
|
||||
* If the entries list is NULL, it will allocate a new list. Caller
|
||||
* is responsible to free it even if an error occurs.
|
||||
*
|
||||
* @param match[in] The host name (with port) to match against
|
||||
* @param filename[in] The known hosts file to parse
|
||||
* @param entries[in,out] The list of entries to append matching ones
|
||||
* @return `SSH_OK` on missing file or success parsing,
|
||||
* `SSH_ERROR` on error
|
||||
*/
|
||||
static int ssh_known_hosts_read_entries(const char *match,
|
||||
const char *filename,
|
||||
@@ -346,6 +357,33 @@ static char *ssh_session_get_host_port(ssh_session session)
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Free known hosts entries list
|
||||
*
|
||||
* @param[in] entry_list The list of ssh_knownhosts_entry items
|
||||
*/
|
||||
static void ssh_knownhosts_entries_free(struct ssh_list *entry_list)
|
||||
{
|
||||
struct ssh_iterator *it = NULL;
|
||||
|
||||
if (entry_list == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (it = ssh_list_get_iterator(entry_list);
|
||||
it != NULL;
|
||||
it = ssh_list_get_iterator(entry_list)) {
|
||||
struct ssh_knownhosts_entry *entry = NULL;
|
||||
|
||||
entry = ssh_iterator_value(struct ssh_knownhosts_entry *, it);
|
||||
ssh_knownhosts_entry_free(entry);
|
||||
ssh_list_remove(entry_list, it);
|
||||
}
|
||||
ssh_list_free(entry_list);
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Check which host keys should be preferred for the session.
|
||||
*
|
||||
* This checks the known_hosts file to find out which algorithms should be
|
||||
@@ -453,7 +491,7 @@ struct ssh_list *ssh_known_hosts_get_algorithms(ssh_session session)
|
||||
|
||||
return list;
|
||||
error:
|
||||
ssh_list_free(entry_list);
|
||||
ssh_knownhosts_entries_free(entry_list);
|
||||
ssh_list_free(list);
|
||||
return NULL;
|
||||
}
|
||||
@@ -505,6 +543,7 @@ static const char *ssh_known_host_sigs_from_hostkey_type(enum ssh_keytypes_e typ
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Get the host keys algorithms identifiers from the known_hosts files
|
||||
*
|
||||
* This expands the signatures types that can be generated from the keys types
|
||||
@@ -549,7 +588,7 @@ char *ssh_known_hosts_get_algorithms_names(ssh_session session)
|
||||
&entry_list);
|
||||
if (rc != 0) {
|
||||
SAFE_FREE(host_port);
|
||||
ssh_list_free(entry_list);
|
||||
ssh_knownhosts_entries_free(entry_list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -558,7 +597,7 @@ char *ssh_known_hosts_get_algorithms_names(ssh_session session)
|
||||
&entry_list);
|
||||
SAFE_FREE(host_port);
|
||||
if (rc != 0) {
|
||||
ssh_list_free(entry_list);
|
||||
ssh_knownhosts_entries_free(entry_list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -799,7 +838,6 @@ out:
|
||||
enum ssh_known_hosts_e ssh_session_has_known_hosts_entry(ssh_session session)
|
||||
{
|
||||
struct ssh_list *entry_list = NULL;
|
||||
struct ssh_iterator *it = NULL;
|
||||
char *host_port = NULL;
|
||||
bool global_known_hosts_found = false;
|
||||
bool known_hosts_found = false;
|
||||
@@ -860,7 +898,7 @@ enum ssh_known_hosts_e ssh_session_has_known_hosts_entry(ssh_session session)
|
||||
&entry_list);
|
||||
if (rc != 0) {
|
||||
SAFE_FREE(host_port);
|
||||
ssh_list_free(entry_list);
|
||||
ssh_knownhosts_entries_free(entry_list);
|
||||
return SSH_KNOWN_HOSTS_ERROR;
|
||||
}
|
||||
}
|
||||
@@ -871,7 +909,7 @@ enum ssh_known_hosts_e ssh_session_has_known_hosts_entry(ssh_session session)
|
||||
&entry_list);
|
||||
if (rc != 0) {
|
||||
SAFE_FREE(host_port);
|
||||
ssh_list_free(entry_list);
|
||||
ssh_knownhosts_entries_free(entry_list);
|
||||
return SSH_KNOWN_HOSTS_ERROR;
|
||||
}
|
||||
}
|
||||
@@ -883,16 +921,7 @@ enum ssh_known_hosts_e ssh_session_has_known_hosts_entry(ssh_session session)
|
||||
return SSH_KNOWN_HOSTS_UNKNOWN;
|
||||
}
|
||||
|
||||
for (it = ssh_list_get_iterator(entry_list);
|
||||
it != NULL;
|
||||
it = ssh_list_get_iterator(entry_list)) {
|
||||
struct ssh_knownhosts_entry *entry = NULL;
|
||||
|
||||
entry = ssh_iterator_value(struct ssh_knownhosts_entry *, it);
|
||||
ssh_knownhosts_entry_free(entry);
|
||||
ssh_list_remove(entry_list, it);
|
||||
}
|
||||
ssh_list_free(entry_list);
|
||||
ssh_knownhosts_entries_free(entry_list);
|
||||
|
||||
return SSH_KNOWN_HOSTS_OK;
|
||||
}
|
||||
@@ -1079,13 +1108,13 @@ ssh_known_hosts_check_server_key(const char *hosts_entry,
|
||||
filename,
|
||||
&entry_list);
|
||||
if (rc != 0) {
|
||||
ssh_list_free(entry_list);
|
||||
ssh_knownhosts_entries_free(entry_list);
|
||||
return SSH_KNOWN_HOSTS_UNKNOWN;
|
||||
}
|
||||
|
||||
it = ssh_list_get_iterator(entry_list);
|
||||
if (it == NULL) {
|
||||
ssh_list_free(entry_list);
|
||||
ssh_knownhosts_entries_free(entry_list);
|
||||
return SSH_KNOWN_HOSTS_UNKNOWN;
|
||||
}
|
||||
|
||||
@@ -1115,16 +1144,7 @@ ssh_known_hosts_check_server_key(const char *hosts_entry,
|
||||
}
|
||||
}
|
||||
|
||||
for (it = ssh_list_get_iterator(entry_list);
|
||||
it != NULL;
|
||||
it = ssh_list_get_iterator(entry_list)) {
|
||||
struct ssh_knownhosts_entry *entry = NULL;
|
||||
|
||||
entry = ssh_iterator_value(struct ssh_knownhosts_entry *, it);
|
||||
ssh_knownhosts_entry_free(entry);
|
||||
ssh_list_remove(entry_list, it);
|
||||
}
|
||||
ssh_list_free(entry_list);
|
||||
ssh_knownhosts_entries_free(entry_list);
|
||||
|
||||
return found;
|
||||
}
|
||||
@@ -1196,6 +1216,8 @@ ssh_session_get_known_hosts_entry(ssh_session session,
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Get the known_hosts entry for the current connected session
|
||||
* from the given known_hosts file.
|
||||
*
|
||||
|
||||
504
src/libcrypto.c
504
src/libcrypto.c
@@ -40,7 +40,9 @@
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBCRYPTO
|
||||
|
||||
#ifdef LIBRESSL_VERSION_NUMBER
|
||||
#include <openssl/poly1305.h>
|
||||
#endif
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/md5.h>
|
||||
#include <openssl/opensslv.h>
|
||||
@@ -572,12 +574,11 @@ static void evp_cipher_cleanup(struct ssh_cipher_struct *cipher) {
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
evp_cipher_aead_get_length(struct ssh_cipher_struct *cipher,
|
||||
void *in,
|
||||
uint8_t *out,
|
||||
size_t len,
|
||||
uint64_t seq)
|
||||
static int evp_cipher_aead_get_length(struct ssh_cipher_struct *cipher,
|
||||
void *in,
|
||||
uint8_t *out,
|
||||
size_t len,
|
||||
uint64_t seq)
|
||||
{
|
||||
(void)cipher;
|
||||
(void)seq;
|
||||
@@ -588,13 +589,12 @@ evp_cipher_aead_get_length(struct ssh_cipher_struct *cipher,
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
evp_cipher_aead_encrypt(struct ssh_cipher_struct *cipher,
|
||||
void *in,
|
||||
void *out,
|
||||
size_t len,
|
||||
uint8_t *tag,
|
||||
uint64_t seq)
|
||||
static void evp_cipher_aead_encrypt(struct ssh_cipher_struct *cipher,
|
||||
void *in,
|
||||
void *out,
|
||||
size_t len,
|
||||
uint8_t *tag,
|
||||
uint64_t seq)
|
||||
{
|
||||
size_t authlen, aadlen;
|
||||
uint8_t lastiv[1];
|
||||
@@ -608,10 +608,7 @@ evp_cipher_aead_encrypt(struct ssh_cipher_struct *cipher,
|
||||
authlen = cipher->tag_size;
|
||||
|
||||
/* increment IV */
|
||||
rc = EVP_CIPHER_CTX_ctrl(cipher->ctx,
|
||||
EVP_CTRL_GCM_IV_GEN,
|
||||
1,
|
||||
lastiv);
|
||||
rc = EVP_CIPHER_CTX_ctrl(cipher->ctx, EVP_CTRL_GCM_IV_GEN, 1, lastiv);
|
||||
if (rc == 0) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "EVP_CTRL_GCM_IV_GEN failed");
|
||||
return;
|
||||
@@ -643,9 +640,7 @@ evp_cipher_aead_encrypt(struct ssh_cipher_struct *cipher,
|
||||
}
|
||||
|
||||
/* compute tag */
|
||||
rc = EVP_EncryptFinal(cipher->ctx,
|
||||
NULL,
|
||||
&tmplen);
|
||||
rc = EVP_EncryptFinal(cipher->ctx, NULL, &tmplen);
|
||||
if (rc < 0) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "EVP_EncryptFinal failed: Failed to create a tag");
|
||||
return;
|
||||
@@ -661,12 +656,11 @@ evp_cipher_aead_encrypt(struct ssh_cipher_struct *cipher,
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
evp_cipher_aead_decrypt(struct ssh_cipher_struct *cipher,
|
||||
void *complete_packet,
|
||||
uint8_t *out,
|
||||
size_t encrypted_size,
|
||||
uint64_t seq)
|
||||
static int evp_cipher_aead_decrypt(struct ssh_cipher_struct *cipher,
|
||||
void *complete_packet,
|
||||
uint8_t *out,
|
||||
size_t encrypted_size,
|
||||
uint64_t seq)
|
||||
{
|
||||
size_t authlen, aadlen;
|
||||
uint8_t lastiv[1];
|
||||
@@ -679,10 +673,7 @@ evp_cipher_aead_decrypt(struct ssh_cipher_struct *cipher,
|
||||
authlen = cipher->tag_size;
|
||||
|
||||
/* increment IV */
|
||||
rc = EVP_CIPHER_CTX_ctrl(cipher->ctx,
|
||||
EVP_CTRL_GCM_IV_GEN,
|
||||
1,
|
||||
lastiv);
|
||||
rc = EVP_CIPHER_CTX_ctrl(cipher->ctx, EVP_CTRL_GCM_IV_GEN, 1, lastiv);
|
||||
if (rc == 0) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "EVP_CTRL_GCM_IV_GEN failed");
|
||||
return SSH_ERROR;
|
||||
@@ -692,7 +683,8 @@ evp_cipher_aead_decrypt(struct ssh_cipher_struct *cipher,
|
||||
rc = EVP_CIPHER_CTX_ctrl(cipher->ctx,
|
||||
EVP_CTRL_GCM_SET_TAG,
|
||||
(int)authlen,
|
||||
(unsigned char *)complete_packet + aadlen + encrypted_size);
|
||||
(unsigned char *)complete_packet + aadlen +
|
||||
encrypted_size);
|
||||
if (rc == 0) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "EVP_CTRL_GCM_SET_TAG failed");
|
||||
return SSH_ERROR;
|
||||
@@ -731,11 +723,10 @@ evp_cipher_aead_decrypt(struct ssh_cipher_struct *cipher,
|
||||
}
|
||||
|
||||
/* verify tag */
|
||||
rc = EVP_DecryptFinal(cipher->ctx,
|
||||
NULL,
|
||||
&outlen);
|
||||
rc = EVP_DecryptFinal(cipher->ctx, NULL, &outlen);
|
||||
if (rc < 0) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "EVP_DecryptFinal failed: Failed authentication");
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"EVP_DecryptFinal failed: Failed authentication");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
@@ -749,7 +740,10 @@ struct chacha20_poly1305_keysched {
|
||||
EVP_CIPHER_CTX *main_evp;
|
||||
/* cipher handle used for encrypting the length field */
|
||||
EVP_CIPHER_CTX *header_evp;
|
||||
#if OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||
#if defined(LIBRESSL_VERSION_NUMBER)
|
||||
/* LibreSSL Poly1305 context */
|
||||
poly1305_context poly_ctx;
|
||||
#elif OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||
/* mac handle used for authenticating the packets */
|
||||
EVP_PKEY_CTX *pctx;
|
||||
/* Poly1305 key */
|
||||
@@ -762,8 +756,7 @@ struct chacha20_poly1305_keysched {
|
||||
#endif /* OPENSSL_VERSION_NUMBER */
|
||||
};
|
||||
|
||||
static void
|
||||
chacha20_poly1305_cleanup(struct ssh_cipher_struct *cipher)
|
||||
static void chacha20_poly1305_cleanup(struct ssh_cipher_struct *cipher)
|
||||
{
|
||||
struct chacha20_poly1305_keysched *ctx = NULL;
|
||||
|
||||
@@ -774,10 +767,12 @@ chacha20_poly1305_cleanup(struct ssh_cipher_struct *cipher)
|
||||
ctx = cipher->chacha20_schedule;
|
||||
|
||||
EVP_CIPHER_CTX_free(ctx->main_evp);
|
||||
ctx->main_evp = NULL;
|
||||
ctx->main_evp = NULL;
|
||||
EVP_CIPHER_CTX_free(ctx->header_evp);
|
||||
ctx->header_evp = NULL;
|
||||
#if OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||
#if defined(LIBRESSL_VERSION_NUMBER)
|
||||
/* nothing to free */
|
||||
#elif OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||
/* ctx->pctx is freed as part of MD context */
|
||||
EVP_PKEY_free(ctx->key);
|
||||
ctx->key = NULL;
|
||||
@@ -791,10 +786,9 @@ chacha20_poly1305_cleanup(struct ssh_cipher_struct *cipher)
|
||||
SAFE_FREE(cipher->chacha20_schedule);
|
||||
}
|
||||
|
||||
static int
|
||||
chacha20_poly1305_set_key(struct ssh_cipher_struct *cipher,
|
||||
void *key,
|
||||
UNUSED_PARAM(void *IV))
|
||||
static int chacha20_poly1305_set_key(struct ssh_cipher_struct *cipher,
|
||||
void *key,
|
||||
UNUSED_PARAM(void *IV))
|
||||
{
|
||||
struct chacha20_poly1305_keysched *ctx = NULL;
|
||||
uint8_t *u8key = key;
|
||||
@@ -841,7 +835,9 @@ chacha20_poly1305_set_key(struct ssh_cipher_struct *cipher,
|
||||
/* The Poly1305 key initialization is delayed to the time we know
|
||||
* the actual key for packet so we do not need to create a bogus keys
|
||||
*/
|
||||
#if OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||
#if defined(LIBRESSL_VERSION_NUMBER)
|
||||
/* nothing, poly1305_context is stack based */
|
||||
#elif OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||
ctx->mctx = EVP_MD_CTX_new();
|
||||
if (ctx->mctx == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "EVP_MD_CTX_new failed");
|
||||
@@ -873,10 +869,9 @@ out:
|
||||
|
||||
static const uint8_t zero_block[CHACHA20_BLOCKSIZE] = {0};
|
||||
|
||||
static int
|
||||
chacha20_poly1305_set_iv(struct ssh_cipher_struct *cipher,
|
||||
uint64_t seq,
|
||||
int do_encrypt)
|
||||
static int chacha20_poly1305_set_iv(struct ssh_cipher_struct *cipher,
|
||||
uint64_t seq,
|
||||
int do_encrypt)
|
||||
{
|
||||
struct chacha20_poly1305_keysched *ctx = cipher->chacha20_schedule;
|
||||
uint8_t seqbuf[16] = {0};
|
||||
@@ -906,10 +901,9 @@ chacha20_poly1305_set_iv(struct ssh_cipher_struct *cipher,
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
chacha20_poly1305_packet_setup(struct ssh_cipher_struct *cipher,
|
||||
uint64_t seq,
|
||||
int do_encrypt)
|
||||
static int chacha20_poly1305_packet_setup(struct ssh_cipher_struct *cipher,
|
||||
uint64_t seq,
|
||||
int do_encrypt)
|
||||
{
|
||||
struct chacha20_poly1305_keysched *ctx = cipher->chacha20_schedule;
|
||||
uint8_t poly_key[CHACHA20_BLOCKSIZE];
|
||||
@@ -935,12 +929,17 @@ chacha20_poly1305_packet_setup(struct ssh_cipher_struct *cipher,
|
||||
ssh_log_hexdump("poly_key", poly_key, POLY1305_KEYLEN);
|
||||
#endif /* DEBUG_CRYPTO */
|
||||
|
||||
/* Set the Poly1305 key */
|
||||
#if OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||
/* LibreSSL path: use direct Poly1305 implementation */
|
||||
#if defined(LIBRESSL_VERSION_NUMBER)
|
||||
CRYPTO_poly1305_init(&ctx->poly_ctx, poly_key);
|
||||
/* Set the Poly1305 key */
|
||||
#elif OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||
if (ctx->key == NULL) {
|
||||
/* Poly1305 Initialization needs to know the actual key */
|
||||
ctx->key = EVP_PKEY_new_mac_key(EVP_PKEY_POLY1305, NULL,
|
||||
poly_key, POLY1305_KEYLEN);
|
||||
ctx->key = EVP_PKEY_new_mac_key(EVP_PKEY_POLY1305,
|
||||
NULL,
|
||||
poly_key,
|
||||
POLY1305_KEYLEN);
|
||||
if (ctx->key == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "EVP_PKEY_new_mac_key failed");
|
||||
goto out;
|
||||
@@ -952,9 +951,12 @@ chacha20_poly1305_packet_setup(struct ssh_cipher_struct *cipher,
|
||||
}
|
||||
} else {
|
||||
/* Updating the key is easier but less obvious */
|
||||
rv = EVP_PKEY_CTX_ctrl(ctx->pctx, -1, EVP_PKEY_OP_SIGNCTX,
|
||||
EVP_PKEY_CTRL_SET_MAC_KEY,
|
||||
POLY1305_KEYLEN, (void *)poly_key);
|
||||
rv = EVP_PKEY_CTX_ctrl(ctx->pctx,
|
||||
-1,
|
||||
EVP_PKEY_OP_SIGNCTX,
|
||||
EVP_PKEY_CTRL_SET_MAC_KEY,
|
||||
POLY1305_KEYLEN,
|
||||
(void *)poly_key);
|
||||
if (rv <= 0) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "EVP_PKEY_CTX_ctrl failed");
|
||||
goto out;
|
||||
@@ -1017,20 +1019,21 @@ chacha20_poly1305_aead_decrypt_length(struct ssh_cipher_struct *cipher,
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
chacha20_poly1305_aead_decrypt(struct ssh_cipher_struct *cipher,
|
||||
void *complete_packet,
|
||||
uint8_t *out,
|
||||
size_t encrypted_size,
|
||||
uint64_t seq)
|
||||
static int chacha20_poly1305_aead_decrypt(struct ssh_cipher_struct *cipher,
|
||||
void *complete_packet,
|
||||
uint8_t *out,
|
||||
size_t encrypted_size,
|
||||
uint64_t seq)
|
||||
{
|
||||
struct chacha20_poly1305_keysched *ctx = cipher->chacha20_schedule;
|
||||
uint8_t *mac = (uint8_t *)complete_packet + sizeof(uint32_t) +
|
||||
encrypted_size;
|
||||
uint8_t *mac =
|
||||
(uint8_t *)complete_packet + sizeof(uint32_t) + encrypted_size;
|
||||
uint8_t tag[POLY1305_TAGLEN] = {0};
|
||||
int ret = SSH_ERROR;
|
||||
int rv, cmp, len = 0;
|
||||
#if !defined(LIBRESSL_VERSION_NUMBER)
|
||||
size_t taglen = POLY1305_TAGLEN;
|
||||
#endif
|
||||
|
||||
/* Prepare the Poly1305 key */
|
||||
rv = chacha20_poly1305_packet_setup(cipher, seq, 0);
|
||||
@@ -1044,7 +1047,13 @@ chacha20_poly1305_aead_decrypt(struct ssh_cipher_struct *cipher,
|
||||
#endif /* DEBUG_CRYPTO */
|
||||
|
||||
/* Calculate MAC of received data */
|
||||
#if OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||
#if defined(LIBRESSL_VERSION_NUMBER)
|
||||
CRYPTO_poly1305_update(&ctx->poly_ctx,
|
||||
complete_packet,
|
||||
encrypted_size + sizeof(uint32_t));
|
||||
CRYPTO_poly1305_finish(&ctx->poly_ctx, tag);
|
||||
|
||||
#elif OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||
rv = EVP_DigestSignUpdate(ctx->mctx, complete_packet,
|
||||
encrypted_size + sizeof(uint32_t));
|
||||
if (rv != 1) {
|
||||
@@ -1058,7 +1067,8 @@ chacha20_poly1305_aead_decrypt(struct ssh_cipher_struct *cipher,
|
||||
goto out;
|
||||
}
|
||||
#else
|
||||
rv = EVP_MAC_update(ctx->mctx, complete_packet,
|
||||
rv = EVP_MAC_update(ctx->mctx,
|
||||
complete_packet,
|
||||
encrypted_size + sizeof(uint32_t));
|
||||
if (rv != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "EVP_MAC_update failed");
|
||||
@@ -1106,17 +1116,18 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
chacha20_poly1305_aead_encrypt(struct ssh_cipher_struct *cipher,
|
||||
void *in,
|
||||
void *out,
|
||||
size_t len,
|
||||
uint8_t *tag,
|
||||
uint64_t seq)
|
||||
static void chacha20_poly1305_aead_encrypt(struct ssh_cipher_struct *cipher,
|
||||
void *in,
|
||||
void *out,
|
||||
size_t len,
|
||||
uint8_t *tag,
|
||||
uint64_t seq)
|
||||
{
|
||||
struct ssh_packet_header *in_packet = in, *out_packet = out;
|
||||
struct chacha20_poly1305_keysched *ctx = cipher->chacha20_schedule;
|
||||
#if !defined(LIBRESSL_VERSION_NUMBER)
|
||||
size_t taglen = POLY1305_TAGLEN;
|
||||
#endif
|
||||
int ret, outlen = 0;
|
||||
|
||||
/* Prepare the Poly1305 key */
|
||||
@@ -1128,7 +1139,8 @@ chacha20_poly1305_aead_encrypt(struct ssh_cipher_struct *cipher,
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_log_hexdump("plaintext length",
|
||||
(unsigned char *)&in_packet->length, sizeof(uint32_t));
|
||||
(unsigned char *)&in_packet->length,
|
||||
sizeof(uint32_t));
|
||||
#endif /* DEBUG_CRYPTO */
|
||||
/* step 2, encrypt length field */
|
||||
ret = EVP_CipherUpdate(ctx->header_evp,
|
||||
@@ -1142,7 +1154,8 @@ chacha20_poly1305_aead_encrypt(struct ssh_cipher_struct *cipher,
|
||||
}
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_log_hexdump("encrypted length",
|
||||
(unsigned char *)&out_packet->length, outlen);
|
||||
(unsigned char *)&out_packet->length,
|
||||
outlen);
|
||||
#endif /* DEBUG_CRYPTO */
|
||||
ret = EVP_CipherFinal_ex(ctx->header_evp, (uint8_t *)out + outlen, &outlen);
|
||||
if (ret != 1 || outlen != 0) {
|
||||
@@ -1163,7 +1176,13 @@ chacha20_poly1305_aead_encrypt(struct ssh_cipher_struct *cipher,
|
||||
}
|
||||
|
||||
/* step 4, compute the MAC */
|
||||
#if OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||
#if defined(LIBRESSL_VERSION_NUMBER)
|
||||
|
||||
CRYPTO_poly1305_update(&ctx->poly_ctx,
|
||||
(const unsigned char *)out_packet,
|
||||
len);
|
||||
CRYPTO_poly1305_finish(&ctx->poly_ctx, tag);
|
||||
#elif OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||
ret = EVP_DigestSignUpdate(ctx->mctx, out_packet, len);
|
||||
if (ret <= 0) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "EVP_DigestSignUpdate failed");
|
||||
@@ -1175,7 +1194,7 @@ chacha20_poly1305_aead_encrypt(struct ssh_cipher_struct *cipher,
|
||||
return;
|
||||
}
|
||||
#else
|
||||
ret = EVP_MAC_update(ctx->mctx, (void*)out_packet, len);
|
||||
ret = EVP_MAC_update(ctx->mctx, (void *)out_packet, len);
|
||||
if (ret != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "EVP_MAC_update failed");
|
||||
return;
|
||||
@@ -1191,11 +1210,10 @@ chacha20_poly1305_aead_encrypt(struct ssh_cipher_struct *cipher,
|
||||
#endif /* HAVE_OPENSSL_EVP_CHACHA20 */
|
||||
|
||||
#ifdef WITH_INSECURE_NONE
|
||||
static void
|
||||
none_crypt(UNUSED_PARAM(struct ssh_cipher_struct *cipher),
|
||||
void *in,
|
||||
void *out,
|
||||
size_t len)
|
||||
static void none_crypt(UNUSED_PARAM(struct ssh_cipher_struct *cipher),
|
||||
void *in,
|
||||
void *out,
|
||||
size_t len)
|
||||
{
|
||||
memcpy(out, in, len);
|
||||
}
|
||||
@@ -1206,163 +1224,163 @@ none_crypt(UNUSED_PARAM(struct ssh_cipher_struct *cipher),
|
||||
*/
|
||||
static struct ssh_cipher_struct ssh_ciphertab[] = {
|
||||
#ifdef HAVE_BLOWFISH
|
||||
{
|
||||
.name = "blowfish-cbc",
|
||||
.blocksize = 8,
|
||||
.ciphertype = SSH_BLOWFISH_CBC,
|
||||
.keysize = 128,
|
||||
.set_encrypt_key = evp_cipher_set_encrypt_key,
|
||||
.set_decrypt_key = evp_cipher_set_decrypt_key,
|
||||
.encrypt = evp_cipher_encrypt,
|
||||
.decrypt = evp_cipher_decrypt,
|
||||
.cleanup = evp_cipher_cleanup
|
||||
},
|
||||
{
|
||||
.name = "blowfish-cbc",
|
||||
.blocksize = 8,
|
||||
.ciphertype = SSH_BLOWFISH_CBC,
|
||||
.keysize = 128,
|
||||
.set_encrypt_key = evp_cipher_set_encrypt_key,
|
||||
.set_decrypt_key = evp_cipher_set_decrypt_key,
|
||||
.encrypt = evp_cipher_encrypt,
|
||||
.decrypt = evp_cipher_decrypt,
|
||||
.cleanup = evp_cipher_cleanup,
|
||||
},
|
||||
#endif /* HAVE_BLOWFISH */
|
||||
#ifdef HAS_AES
|
||||
{
|
||||
.name = "aes128-ctr",
|
||||
.blocksize = AES_BLOCK_SIZE,
|
||||
.ciphertype = SSH_AES128_CTR,
|
||||
.keysize = 128,
|
||||
.set_encrypt_key = evp_cipher_set_encrypt_key,
|
||||
.set_decrypt_key = evp_cipher_set_decrypt_key,
|
||||
.encrypt = evp_cipher_encrypt,
|
||||
.decrypt = evp_cipher_decrypt,
|
||||
.cleanup = evp_cipher_cleanup
|
||||
},
|
||||
{
|
||||
.name = "aes192-ctr",
|
||||
.blocksize = AES_BLOCK_SIZE,
|
||||
.ciphertype = SSH_AES192_CTR,
|
||||
.keysize = 192,
|
||||
.set_encrypt_key = evp_cipher_set_encrypt_key,
|
||||
.set_decrypt_key = evp_cipher_set_decrypt_key,
|
||||
.encrypt = evp_cipher_encrypt,
|
||||
.decrypt = evp_cipher_decrypt,
|
||||
.cleanup = evp_cipher_cleanup
|
||||
},
|
||||
{
|
||||
.name = "aes256-ctr",
|
||||
.blocksize = AES_BLOCK_SIZE,
|
||||
.ciphertype = SSH_AES256_CTR,
|
||||
.keysize = 256,
|
||||
.set_encrypt_key = evp_cipher_set_encrypt_key,
|
||||
.set_decrypt_key = evp_cipher_set_decrypt_key,
|
||||
.encrypt = evp_cipher_encrypt,
|
||||
.decrypt = evp_cipher_decrypt,
|
||||
.cleanup = evp_cipher_cleanup
|
||||
},
|
||||
{
|
||||
.name = "aes128-cbc",
|
||||
.blocksize = AES_BLOCK_SIZE,
|
||||
.ciphertype = SSH_AES128_CBC,
|
||||
.keysize = 128,
|
||||
.set_encrypt_key = evp_cipher_set_encrypt_key,
|
||||
.set_decrypt_key = evp_cipher_set_decrypt_key,
|
||||
.encrypt = evp_cipher_encrypt,
|
||||
.decrypt = evp_cipher_decrypt,
|
||||
.cleanup = evp_cipher_cleanup
|
||||
},
|
||||
{
|
||||
.name = "aes192-cbc",
|
||||
.blocksize = AES_BLOCK_SIZE,
|
||||
.ciphertype = SSH_AES192_CBC,
|
||||
.keysize = 192,
|
||||
.set_encrypt_key = evp_cipher_set_encrypt_key,
|
||||
.set_decrypt_key = evp_cipher_set_decrypt_key,
|
||||
.encrypt = evp_cipher_encrypt,
|
||||
.decrypt = evp_cipher_decrypt,
|
||||
.cleanup = evp_cipher_cleanup
|
||||
},
|
||||
{
|
||||
.name = "aes256-cbc",
|
||||
.blocksize = AES_BLOCK_SIZE,
|
||||
.ciphertype = SSH_AES256_CBC,
|
||||
.keysize = 256,
|
||||
.set_encrypt_key = evp_cipher_set_encrypt_key,
|
||||
.set_decrypt_key = evp_cipher_set_decrypt_key,
|
||||
.encrypt = evp_cipher_encrypt,
|
||||
.decrypt = evp_cipher_decrypt,
|
||||
.cleanup = evp_cipher_cleanup
|
||||
},
|
||||
{
|
||||
.name = "aes128-gcm@openssh.com",
|
||||
.blocksize = AES_BLOCK_SIZE,
|
||||
.lenfield_blocksize = 4, /* not encrypted, but authenticated */
|
||||
.ciphertype = SSH_AEAD_AES128_GCM,
|
||||
.keysize = 128,
|
||||
.tag_size = AES_GCM_TAGLEN,
|
||||
.set_encrypt_key = evp_cipher_set_encrypt_key,
|
||||
.set_decrypt_key = evp_cipher_set_decrypt_key,
|
||||
.aead_encrypt = evp_cipher_aead_encrypt,
|
||||
.aead_decrypt_length = evp_cipher_aead_get_length,
|
||||
.aead_decrypt = evp_cipher_aead_decrypt,
|
||||
.cleanup = evp_cipher_cleanup
|
||||
},
|
||||
{
|
||||
.name = "aes256-gcm@openssh.com",
|
||||
.blocksize = AES_BLOCK_SIZE,
|
||||
.lenfield_blocksize = 4, /* not encrypted, but authenticated */
|
||||
.ciphertype = SSH_AEAD_AES256_GCM,
|
||||
.keysize = 256,
|
||||
.tag_size = AES_GCM_TAGLEN,
|
||||
.set_encrypt_key = evp_cipher_set_encrypt_key,
|
||||
.set_decrypt_key = evp_cipher_set_decrypt_key,
|
||||
.aead_encrypt = evp_cipher_aead_encrypt,
|
||||
.aead_decrypt_length = evp_cipher_aead_get_length,
|
||||
.aead_decrypt = evp_cipher_aead_decrypt,
|
||||
.cleanup = evp_cipher_cleanup
|
||||
},
|
||||
{
|
||||
.name = "aes128-ctr",
|
||||
.blocksize = AES_BLOCK_SIZE,
|
||||
.ciphertype = SSH_AES128_CTR,
|
||||
.keysize = 128,
|
||||
.set_encrypt_key = evp_cipher_set_encrypt_key,
|
||||
.set_decrypt_key = evp_cipher_set_decrypt_key,
|
||||
.encrypt = evp_cipher_encrypt,
|
||||
.decrypt = evp_cipher_decrypt,
|
||||
.cleanup = evp_cipher_cleanup,
|
||||
},
|
||||
{
|
||||
.name = "aes192-ctr",
|
||||
.blocksize = AES_BLOCK_SIZE,
|
||||
.ciphertype = SSH_AES192_CTR,
|
||||
.keysize = 192,
|
||||
.set_encrypt_key = evp_cipher_set_encrypt_key,
|
||||
.set_decrypt_key = evp_cipher_set_decrypt_key,
|
||||
.encrypt = evp_cipher_encrypt,
|
||||
.decrypt = evp_cipher_decrypt,
|
||||
.cleanup = evp_cipher_cleanup,
|
||||
},
|
||||
{
|
||||
.name = "aes256-ctr",
|
||||
.blocksize = AES_BLOCK_SIZE,
|
||||
.ciphertype = SSH_AES256_CTR,
|
||||
.keysize = 256,
|
||||
.set_encrypt_key = evp_cipher_set_encrypt_key,
|
||||
.set_decrypt_key = evp_cipher_set_decrypt_key,
|
||||
.encrypt = evp_cipher_encrypt,
|
||||
.decrypt = evp_cipher_decrypt,
|
||||
.cleanup = evp_cipher_cleanup,
|
||||
},
|
||||
{
|
||||
.name = "aes128-cbc",
|
||||
.blocksize = AES_BLOCK_SIZE,
|
||||
.ciphertype = SSH_AES128_CBC,
|
||||
.keysize = 128,
|
||||
.set_encrypt_key = evp_cipher_set_encrypt_key,
|
||||
.set_decrypt_key = evp_cipher_set_decrypt_key,
|
||||
.encrypt = evp_cipher_encrypt,
|
||||
.decrypt = evp_cipher_decrypt,
|
||||
.cleanup = evp_cipher_cleanup,
|
||||
},
|
||||
{
|
||||
.name = "aes192-cbc",
|
||||
.blocksize = AES_BLOCK_SIZE,
|
||||
.ciphertype = SSH_AES192_CBC,
|
||||
.keysize = 192,
|
||||
.set_encrypt_key = evp_cipher_set_encrypt_key,
|
||||
.set_decrypt_key = evp_cipher_set_decrypt_key,
|
||||
.encrypt = evp_cipher_encrypt,
|
||||
.decrypt = evp_cipher_decrypt,
|
||||
.cleanup = evp_cipher_cleanup,
|
||||
},
|
||||
{
|
||||
.name = "aes256-cbc",
|
||||
.blocksize = AES_BLOCK_SIZE,
|
||||
.ciphertype = SSH_AES256_CBC,
|
||||
.keysize = 256,
|
||||
.set_encrypt_key = evp_cipher_set_encrypt_key,
|
||||
.set_decrypt_key = evp_cipher_set_decrypt_key,
|
||||
.encrypt = evp_cipher_encrypt,
|
||||
.decrypt = evp_cipher_decrypt,
|
||||
.cleanup = evp_cipher_cleanup,
|
||||
},
|
||||
{
|
||||
.name = "aes128-gcm@openssh.com",
|
||||
.blocksize = AES_BLOCK_SIZE,
|
||||
.lenfield_blocksize = 4, /* not encrypted, but authenticated */
|
||||
.ciphertype = SSH_AEAD_AES128_GCM,
|
||||
.keysize = 128,
|
||||
.tag_size = AES_GCM_TAGLEN,
|
||||
.set_encrypt_key = evp_cipher_set_encrypt_key,
|
||||
.set_decrypt_key = evp_cipher_set_decrypt_key,
|
||||
.aead_encrypt = evp_cipher_aead_encrypt,
|
||||
.aead_decrypt_length = evp_cipher_aead_get_length,
|
||||
.aead_decrypt = evp_cipher_aead_decrypt,
|
||||
.cleanup = evp_cipher_cleanup,
|
||||
},
|
||||
{
|
||||
.name = "aes256-gcm@openssh.com",
|
||||
.blocksize = AES_BLOCK_SIZE,
|
||||
.lenfield_blocksize = 4, /* not encrypted, but authenticated */
|
||||
.ciphertype = SSH_AEAD_AES256_GCM,
|
||||
.keysize = 256,
|
||||
.tag_size = AES_GCM_TAGLEN,
|
||||
.set_encrypt_key = evp_cipher_set_encrypt_key,
|
||||
.set_decrypt_key = evp_cipher_set_decrypt_key,
|
||||
.aead_encrypt = evp_cipher_aead_encrypt,
|
||||
.aead_decrypt_length = evp_cipher_aead_get_length,
|
||||
.aead_decrypt = evp_cipher_aead_decrypt,
|
||||
.cleanup = evp_cipher_cleanup,
|
||||
},
|
||||
#endif /* HAS_AES */
|
||||
#ifdef HAS_DES
|
||||
{
|
||||
.name = "3des-cbc",
|
||||
.blocksize = 8,
|
||||
.ciphertype = SSH_3DES_CBC,
|
||||
.keysize = 192,
|
||||
.set_encrypt_key = evp_cipher_set_encrypt_key,
|
||||
.set_decrypt_key = evp_cipher_set_decrypt_key,
|
||||
.encrypt = evp_cipher_encrypt,
|
||||
.decrypt = evp_cipher_decrypt,
|
||||
.cleanup = evp_cipher_cleanup
|
||||
},
|
||||
{
|
||||
.name = "3des-cbc",
|
||||
.blocksize = 8,
|
||||
.ciphertype = SSH_3DES_CBC,
|
||||
.keysize = 192,
|
||||
.set_encrypt_key = evp_cipher_set_encrypt_key,
|
||||
.set_decrypt_key = evp_cipher_set_decrypt_key,
|
||||
.encrypt = evp_cipher_encrypt,
|
||||
.decrypt = evp_cipher_decrypt,
|
||||
.cleanup = evp_cipher_cleanup,
|
||||
},
|
||||
#endif /* HAS_DES */
|
||||
{
|
||||
{
|
||||
#ifdef HAVE_OPENSSL_EVP_CHACHA20
|
||||
.ciphertype = SSH_AEAD_CHACHA20_POLY1305,
|
||||
.name = "chacha20-poly1305@openssh.com",
|
||||
.blocksize = CHACHA20_BLOCKSIZE/8,
|
||||
.lenfield_blocksize = 4,
|
||||
.keylen = sizeof(struct chacha20_poly1305_keysched),
|
||||
.keysize = 2 * CHACHA20_KEYLEN * 8,
|
||||
.tag_size = POLY1305_TAGLEN,
|
||||
.set_encrypt_key = chacha20_poly1305_set_key,
|
||||
.set_decrypt_key = chacha20_poly1305_set_key,
|
||||
.aead_encrypt = chacha20_poly1305_aead_encrypt,
|
||||
.aead_decrypt_length = chacha20_poly1305_aead_decrypt_length,
|
||||
.aead_decrypt = chacha20_poly1305_aead_decrypt,
|
||||
.cleanup = chacha20_poly1305_cleanup
|
||||
.ciphertype = SSH_AEAD_CHACHA20_POLY1305,
|
||||
.name = "chacha20-poly1305@openssh.com",
|
||||
.blocksize = CHACHA20_BLOCKSIZE / 8,
|
||||
.lenfield_blocksize = 4,
|
||||
.keylen = sizeof(struct chacha20_poly1305_keysched),
|
||||
.keysize = 2 * CHACHA20_KEYLEN * 8,
|
||||
.tag_size = POLY1305_TAGLEN,
|
||||
.set_encrypt_key = chacha20_poly1305_set_key,
|
||||
.set_decrypt_key = chacha20_poly1305_set_key,
|
||||
.aead_encrypt = chacha20_poly1305_aead_encrypt,
|
||||
.aead_decrypt_length = chacha20_poly1305_aead_decrypt_length,
|
||||
.aead_decrypt = chacha20_poly1305_aead_decrypt,
|
||||
.cleanup = chacha20_poly1305_cleanup
|
||||
#else
|
||||
.name = "chacha20-poly1305@openssh.com"
|
||||
.name = "chacha20-poly1305@openssh.com"
|
||||
#endif /* HAVE_OPENSSL_EVP_CHACHA20 */
|
||||
},
|
||||
},
|
||||
#ifdef WITH_INSECURE_NONE
|
||||
{
|
||||
.name = "none",
|
||||
.blocksize = 8,
|
||||
.keysize = 0,
|
||||
.encrypt = none_crypt,
|
||||
.decrypt = none_crypt,
|
||||
},
|
||||
{
|
||||
.name = "none",
|
||||
.blocksize = 8,
|
||||
.keysize = 0,
|
||||
.encrypt = none_crypt,
|
||||
.decrypt = none_crypt,
|
||||
},
|
||||
#endif /* WITH_INSECURE_NONE */
|
||||
{
|
||||
.name = NULL
|
||||
}
|
||||
{
|
||||
.name = NULL,
|
||||
},
|
||||
};
|
||||
|
||||
struct ssh_cipher_struct *ssh_get_ciphertab(void)
|
||||
{
|
||||
return ssh_ciphertab;
|
||||
return ssh_ciphertab;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1378,19 +1396,19 @@ int ssh_crypto_init(void)
|
||||
if (libcrypto_initialized) {
|
||||
return SSH_OK;
|
||||
}
|
||||
if (OpenSSL_version_num() != OPENSSL_VERSION_NUMBER){
|
||||
SSH_LOG(SSH_LOG_DEBUG, "libssh compiled with %s "
|
||||
"headers, currently running with %s.",
|
||||
OPENSSL_VERSION_TEXT,
|
||||
OpenSSL_version(OpenSSL_version_num())
|
||||
);
|
||||
if (OpenSSL_version_num() != OPENSSL_VERSION_NUMBER) {
|
||||
SSH_LOG(SSH_LOG_DEBUG,
|
||||
"libssh compiled with %s "
|
||||
"headers, currently running with %s.",
|
||||
OPENSSL_VERSION_TEXT,
|
||||
OpenSSL_version(OpenSSL_version_num()));
|
||||
}
|
||||
#ifdef CAN_DISABLE_AESNI
|
||||
/*
|
||||
* disable AES-NI when running within Valgrind, because they generate
|
||||
* too many "uninitialized memory access" false positives
|
||||
*/
|
||||
if (RUNNING_ON_VALGRIND){
|
||||
if (RUNNING_ON_VALGRIND) {
|
||||
SSH_LOG(SSH_LOG_INFO, "Running within Valgrind, disabling AES-NI");
|
||||
/* Bit #57 denotes AES-NI instruction set extension */
|
||||
OPENSSL_ia32cap &= ~(1LL << 57);
|
||||
@@ -1453,7 +1471,8 @@ void ssh_crypto_finalize(void)
|
||||
* @internal
|
||||
* @brief Create EVP_PKEY from parameters
|
||||
*
|
||||
* @param[in] name Algorithm to use. For more info see manpage of EVP_PKEY_CTX_new_from_name
|
||||
* @param[in] name Algorithm to use. For more info see manpage of
|
||||
* EVP_PKEY_CTX_new_from_name
|
||||
*
|
||||
* @param[in] param_bld Constructed param builder for the pkey
|
||||
*
|
||||
@@ -1463,8 +1482,10 @@ void ssh_crypto_finalize(void)
|
||||
*
|
||||
* @return 0 on success, -1 on error
|
||||
*/
|
||||
int evp_build_pkey(const char* name, OSSL_PARAM_BLD *param_bld,
|
||||
EVP_PKEY **pkey, int selection)
|
||||
int evp_build_pkey(const char *name,
|
||||
OSSL_PARAM_BLD *param_bld,
|
||||
EVP_PKEY **pkey,
|
||||
int selection)
|
||||
{
|
||||
int rc;
|
||||
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name(NULL, name, NULL);
|
||||
@@ -1596,8 +1617,7 @@ int evp_dup_ed25519_pkey(const ssh_key key, ssh_key new_key, int demote)
|
||||
|
||||
#endif /* OPENSSL_VERSION_NUMBER */
|
||||
|
||||
ssh_string
|
||||
pki_key_make_ecpoint_string(const EC_GROUP *g, const EC_POINT *p)
|
||||
ssh_string pki_key_make_ecpoint_string(const EC_GROUP *g, const EC_POINT *p)
|
||||
{
|
||||
ssh_string s = NULL;
|
||||
size_t len;
|
||||
|
||||
12
src/misc.c
12
src/misc.c
@@ -814,7 +814,17 @@ static struct ssh_iterator *ssh_iterator_new(const void *data)
|
||||
return iterator;
|
||||
}
|
||||
|
||||
int ssh_list_append(struct ssh_list *list,const void *data)
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Appends an element to the end of the list.
|
||||
*
|
||||
* @param[in] list The list to append the element
|
||||
* @param[in] data The element to append
|
||||
*
|
||||
* @return `SSH_OK` on success, `SSH_ERROR` on error
|
||||
*/
|
||||
int ssh_list_append(struct ssh_list *list, const void *data)
|
||||
{
|
||||
struct ssh_iterator *iterator = NULL;
|
||||
|
||||
|
||||
@@ -549,17 +549,14 @@ static sftp_attributes sftp_parse_attr_3(sftp_session sftp,
|
||||
if (rc != SSH_OK){
|
||||
goto error;
|
||||
}
|
||||
SSH_LOG(SSH_LOG_DEBUG,
|
||||
"Flags: %.8" PRIx32 "\n", attr->flags);
|
||||
SSH_LOG(SSH_LOG_DEBUG, "Flags: %.8" PRIx32, attr->flags);
|
||||
|
||||
if (attr->flags & SSH_FILEXFER_ATTR_SIZE) {
|
||||
rc = ssh_buffer_unpack(buf, "q", &attr->size);
|
||||
if(rc != SSH_OK) {
|
||||
goto error;
|
||||
}
|
||||
SSH_LOG(SSH_LOG_DEBUG,
|
||||
"Size: %" PRIu64 "\n",
|
||||
(uint64_t) attr->size);
|
||||
SSH_LOG(SSH_LOG_DEBUG, "Size: %" PRIu64, (uint64_t)attr->size);
|
||||
}
|
||||
|
||||
if (attr->flags & SSH_FILEXFER_ATTR_UIDGID) {
|
||||
|
||||
218
src/socket.c
218
src/socket.c
@@ -97,6 +97,10 @@ struct ssh_socket_struct {
|
||||
struct jump_thread_data_struct {
|
||||
ssh_session session;
|
||||
socket_t fd;
|
||||
char *next_hostname;
|
||||
uint16_t next_port;
|
||||
struct ssh_jump_info_struct *next_jump;
|
||||
struct ssh_jump_callbacks_struct *next_cb;
|
||||
};
|
||||
|
||||
int proxy_disconnect = 0;
|
||||
@@ -1249,6 +1253,22 @@ verify_knownhost(ssh_session session)
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
static void free_jump_thread_data(struct jump_thread_data_struct *data)
|
||||
{
|
||||
if (data == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
ssh_free(data->session);
|
||||
SAFE_FREE(data->next_hostname);
|
||||
if (data->next_jump != NULL) {
|
||||
SAFE_FREE(data->next_jump->hostname);
|
||||
SAFE_FREE(data->next_jump->username);
|
||||
}
|
||||
SAFE_FREE(data->next_jump);
|
||||
SAFE_FREE(data);
|
||||
}
|
||||
|
||||
static void *
|
||||
jump_thread_func(void *arg)
|
||||
{
|
||||
@@ -1260,72 +1280,30 @@ jump_thread_func(void *arg)
|
||||
int rc;
|
||||
ssh_event event = NULL;
|
||||
ssh_connector connector_in = NULL, connector_out = NULL;
|
||||
ssh_session session = NULL;
|
||||
int next_port;
|
||||
uint16_t next_port;
|
||||
char *next_hostname = NULL;
|
||||
|
||||
jump_thread_data = (struct jump_thread_data_struct *)arg;
|
||||
session = jump_thread_data->session;
|
||||
jump_session = jump_thread_data->session;
|
||||
|
||||
next_port = session->opts.port;
|
||||
next_hostname = strdup(session->opts.host);
|
||||
/* First thing we need to do is to set the right level as its kept in
|
||||
* thread local variable, therefore reset to 0 after spawning new thread.
|
||||
*/
|
||||
ssh_set_log_level(jump_session->common.log_verbosity);
|
||||
|
||||
jump_session = ssh_new();
|
||||
if (jump_session == NULL) {
|
||||
goto exit;
|
||||
}
|
||||
cb = jump_thread_data->next_cb;
|
||||
jis = jump_thread_data->next_jump;
|
||||
|
||||
jump_session->proxy_root = false;
|
||||
/* Reset the global variable if it was previously 1 */
|
||||
if (session->proxy_root) {
|
||||
proxy_disconnect = 0;
|
||||
}
|
||||
|
||||
for (jis = ssh_list_pop_head(struct ssh_jump_info_struct *,
|
||||
session->opts.proxy_jumps);
|
||||
jis != NULL;
|
||||
jis = ssh_list_pop_head(struct ssh_jump_info_struct *,
|
||||
session->opts.proxy_jumps)) {
|
||||
rc = ssh_list_append(jump_session->opts.proxy_jumps, jis);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error_oom(session);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
for (jis =
|
||||
ssh_list_pop_head(struct ssh_jump_info_struct *,
|
||||
session->opts.proxy_jumps_user_cb);
|
||||
jis != NULL;
|
||||
jis = ssh_list_pop_head(struct ssh_jump_info_struct *,
|
||||
session->opts.proxy_jumps_user_cb)) {
|
||||
rc = ssh_list_append(jump_session->opts.proxy_jumps_user_cb, jis);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error_oom(session);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
ssh_options_set(jump_session,
|
||||
SSH_OPTIONS_LOG_VERBOSITY,
|
||||
&session->common.log_verbosity);
|
||||
|
||||
/* Pop the information about the current jump */
|
||||
jis = ssh_list_pop_head(struct ssh_jump_info_struct *,
|
||||
jump_session->opts.proxy_jumps);
|
||||
if (jis == NULL) {
|
||||
SSH_LOG(SSH_LOG_WARN, "Inconsistent list of proxy jumps received");
|
||||
goto exit;
|
||||
}
|
||||
/* This is the calling thread target where we will eventually initialize
|
||||
* forwarding */
|
||||
next_port = jump_thread_data->next_port;
|
||||
next_hostname = jump_thread_data->next_hostname;
|
||||
|
||||
ssh_options_set(jump_session, SSH_OPTIONS_HOST, jis->hostname);
|
||||
ssh_options_set(jump_session, SSH_OPTIONS_USER, jis->username);
|
||||
ssh_options_set(jump_session, SSH_OPTIONS_PORT, &jis->port);
|
||||
|
||||
/* Pop the callbacks for the current jump */
|
||||
cb = ssh_list_pop_head(struct ssh_jump_callbacks_struct *,
|
||||
jump_session->opts.proxy_jumps_user_cb);
|
||||
|
||||
if (cb != NULL) {
|
||||
if (cb != NULL && cb->before_connection != NULL) {
|
||||
rc = cb->before_connection(jump_session, cb->userdata);
|
||||
if (rc != SSH_OK) {
|
||||
SSH_LOG(SSH_LOG_WARN, "%s", ssh_get_error(jump_session));
|
||||
@@ -1333,6 +1311,13 @@ jump_thread_func(void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PACKET,
|
||||
"Proxy connecting to host %s port %d user %s, callbacks=%p",
|
||||
jis->hostname,
|
||||
jis->port,
|
||||
jis->username,
|
||||
(void *)cb);
|
||||
|
||||
/* If there are more jumps then this will make a new thread and call the
|
||||
* current function again, until there are no jumps. When there are no jumps
|
||||
* it connects normally. */
|
||||
@@ -1423,36 +1408,42 @@ exit:
|
||||
ssh_event_remove_connector(event, connector_out);
|
||||
ssh_connector_free(connector_out);
|
||||
}
|
||||
SAFE_FREE(next_hostname);
|
||||
if (jis != NULL) {
|
||||
SAFE_FREE(jis->hostname);
|
||||
SAFE_FREE(jis->username);
|
||||
}
|
||||
SAFE_FREE(jis);
|
||||
|
||||
ssh_disconnect(jump_session);
|
||||
ssh_event_free(event);
|
||||
ssh_free(jump_session);
|
||||
|
||||
shutdown(jump_thread_data->fd, SHUT_RDWR);
|
||||
close(jump_thread_data->fd);
|
||||
SAFE_FREE(jump_thread_data);
|
||||
|
||||
free_jump_thread_data(jump_thread_data);
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
int
|
||||
ssh_socket_connect_proxyjump(ssh_socket s)
|
||||
{
|
||||
char err_msg[SSH_ERRNO_MSG_MAX] = {0};
|
||||
ssh_poll_handle h = NULL;
|
||||
int rc;
|
||||
pthread_t jump_thread;
|
||||
struct ssh_jump_info_struct *jis = NULL;
|
||||
struct ssh_jump_callbacks_struct *cb = NULL;
|
||||
struct jump_thread_data_struct *jump_thread_data = NULL;
|
||||
socket_t pair[2];
|
||||
ssh_session jump_session = NULL, session = NULL;
|
||||
struct ssh_list *empty_list = NULL;
|
||||
socket_t pair[2] = {SSH_INVALID_SOCKET, SSH_INVALID_SOCKET};
|
||||
|
||||
session = s->session;
|
||||
|
||||
SSH_LOG(SSH_LOG_INFO,
|
||||
"Connecting to host %s port %d user %s through ProxyJump",
|
||||
session->opts.host,
|
||||
session->opts.port,
|
||||
session->opts.username);
|
||||
|
||||
if (s->state != SSH_SOCKET_NONE) {
|
||||
ssh_set_error(
|
||||
s->session,
|
||||
session,
|
||||
SSH_FATAL,
|
||||
"ssh_socket_connect_proxyjump called on socket not unconnected");
|
||||
return SSH_ERROR;
|
||||
@@ -1460,50 +1451,100 @@ ssh_socket_connect_proxyjump(ssh_socket s)
|
||||
|
||||
jump_thread_data = calloc(1, sizeof(struct jump_thread_data_struct));
|
||||
if (jump_thread_data == NULL) {
|
||||
ssh_set_error_oom(s->session);
|
||||
ssh_set_error_oom(session);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = socketpair(PF_UNIX, SOCK_STREAM, 0, pair);
|
||||
if (rc == -1) {
|
||||
char err_msg[SSH_ERRNO_MSG_MAX] = {0};
|
||||
|
||||
ssh_set_error(s->session,
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Creating socket pair failed: %s",
|
||||
ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
|
||||
SAFE_FREE(jump_thread_data);
|
||||
return SSH_ERROR;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
jump_thread_data->session = s->session;
|
||||
jump_session = ssh_new();
|
||||
if (jump_session == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
jump_session->proxy_root = false;
|
||||
/* Reset the global variable if it was previously 1 */
|
||||
if (session->proxy_root) {
|
||||
proxy_disconnect = 0;
|
||||
}
|
||||
|
||||
/* Pop first jump that will be used by the following thread */
|
||||
jis = ssh_list_pop_head(struct ssh_jump_info_struct *,
|
||||
session->opts.proxy_jumps);
|
||||
if (jis == NULL) {
|
||||
SSH_LOG(SSH_LOG_WARN, "Inconsistent list of proxy jumps received");
|
||||
ssh_free(jump_session);
|
||||
goto fail;
|
||||
}
|
||||
jump_thread_data->next_jump = jis;
|
||||
/* Move remaining to the jump session without reallocation.
|
||||
* The list in the new jump_session is just allocated so empty */
|
||||
empty_list = jump_session->opts.proxy_jumps;
|
||||
jump_session->opts.proxy_jumps = session->opts.proxy_jumps;
|
||||
session->opts.proxy_jumps = empty_list;
|
||||
|
||||
/* Pop the callbacks for the first jump */
|
||||
cb = ssh_list_pop_head(struct ssh_jump_callbacks_struct *,
|
||||
session->opts.proxy_jumps_user_cb);
|
||||
/* empty is ok */
|
||||
jump_thread_data->next_cb = cb;
|
||||
/* Move remaining to the jump session without reallocation.
|
||||
* The list in the new jump_session is just allocated so empty */
|
||||
empty_list = jump_session->opts.proxy_jumps_user_cb;
|
||||
jump_session->opts.proxy_jumps_user_cb = session->opts.proxy_jumps_user_cb;
|
||||
session->opts.proxy_jumps_user_cb = empty_list;
|
||||
|
||||
ssh_options_set(jump_session,
|
||||
SSH_OPTIONS_LOG_VERBOSITY,
|
||||
&session->common.log_verbosity);
|
||||
|
||||
jump_thread_data->next_port = session->opts.port;
|
||||
jump_thread_data->next_hostname = strdup(session->opts.host);
|
||||
|
||||
jump_thread_data->fd = pair[0];
|
||||
pair[0] = SSH_INVALID_SOCKET;
|
||||
jump_thread_data->session = jump_session;
|
||||
/* transferred to the jump_thread_data */
|
||||
jump_session = NULL;
|
||||
|
||||
SSH_LOG(SSH_LOG_INFO,
|
||||
"Starting proxy thread to host %s port %d user %s, callbacks=%p",
|
||||
jump_thread_data->next_jump->hostname,
|
||||
jump_thread_data->next_jump->port,
|
||||
jump_thread_data->next_jump->username,
|
||||
(void *)jump_thread_data->next_cb);
|
||||
|
||||
rc = pthread_create(&jump_thread, NULL, jump_thread_func, jump_thread_data);
|
||||
if (rc != 0) {
|
||||
char err_msg[SSH_ERRNO_MSG_MAX] = {0};
|
||||
|
||||
ssh_set_error(s->session,
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Creating new thread failed: %s",
|
||||
ssh_strerror(rc, err_msg, SSH_ERRNO_MSG_MAX));
|
||||
SAFE_FREE(jump_thread_data);
|
||||
return SSH_ERROR;
|
||||
goto fail;
|
||||
}
|
||||
/* ownership passed to the thread */
|
||||
jump_thread_data = NULL;
|
||||
|
||||
rc = pthread_detach(jump_thread);
|
||||
if (rc != 0) {
|
||||
char err_msg[SSH_ERRNO_MSG_MAX] = {0};
|
||||
|
||||
ssh_set_error(s->session,
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Failed to detach thread: %s",
|
||||
ssh_strerror(rc, err_msg, SSH_ERRNO_MSG_MAX));
|
||||
SAFE_FREE(jump_thread_data);
|
||||
return SSH_ERROR;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_DEBUG,
|
||||
"ProxyJump connection pipe: [%d,%d]",
|
||||
"ProxyJump connection thread %lu started pipe: [%d,%d]",
|
||||
(unsigned long)jump_thread,
|
||||
pair[0],
|
||||
pair[1]);
|
||||
|
||||
@@ -1511,6 +1552,7 @@ ssh_socket_connect_proxyjump(ssh_socket s)
|
||||
if (rc != SSH_OK) {
|
||||
return rc;
|
||||
}
|
||||
pair[1] = SSH_INVALID_SOCKET;
|
||||
|
||||
s->fd_is_socket = 1;
|
||||
h = ssh_socket_get_poll_handle(s);
|
||||
@@ -1525,6 +1567,16 @@ ssh_socket_connect_proxyjump(ssh_socket s)
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
|
||||
fail:
|
||||
if (pair[0] != SSH_INVALID_SOCKET) {
|
||||
close(pair[0]);
|
||||
}
|
||||
if (pair[1] != SSH_INVALID_SOCKET) {
|
||||
close(pair[1]);
|
||||
}
|
||||
free_jump_thread_data(jump_thread_data);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
#endif /* HAVE_PTHREAD */
|
||||
|
||||
@@ -394,6 +394,7 @@ if (CLIENT_TESTING OR SERVER_TESTING)
|
||||
# Allow to auth with bob's public keys on alice and doe account
|
||||
configure_file(keys/id_rsa.pub ${CMAKE_CURRENT_BINARY_DIR}/home/alice/.ssh/authorized_keys @ONLY)
|
||||
configure_file(keys/id_rsa.pub ${CMAKE_CURRENT_BINARY_DIR}/home/doe/.ssh/authorized_keys @ONLY)
|
||||
configure_file(keys/id_ecdsa.pub ${CMAKE_CURRENT_BINARY_DIR}/home/frank/.ssh/authorized_keys @ONLY)
|
||||
|
||||
# append ECDSA public key
|
||||
file(READ keys/id_ecdsa.pub CONTENTS)
|
||||
|
||||
@@ -121,6 +121,50 @@ static int authenticate(ssh_session jump_session, void *user)
|
||||
return ssh_userauth_publickey_auto(jump_session, NULL, NULL);
|
||||
}
|
||||
|
||||
static int authenticate_doe(ssh_session jump_session, void *user)
|
||||
{
|
||||
ssh_key pkey = NULL;
|
||||
char bob_ssh_key[1024];
|
||||
struct passwd *pwd = NULL;
|
||||
int rc;
|
||||
|
||||
(void)user;
|
||||
|
||||
pwd = getpwnam("bob");
|
||||
assert_non_null(pwd);
|
||||
|
||||
snprintf(bob_ssh_key, sizeof(bob_ssh_key), "%s/.ssh/id_rsa", pwd->pw_dir);
|
||||
|
||||
rc = ssh_pki_import_privkey_file(bob_ssh_key, NULL, NULL, NULL, &pkey);
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
|
||||
rc = ssh_userauth_publickey(jump_session, NULL, pkey);
|
||||
ssh_key_free(pkey);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int authenticate_frank(ssh_session jump_session, void *user)
|
||||
{
|
||||
ssh_key pkey = NULL;
|
||||
char bob_ssh_key[1024];
|
||||
struct passwd *pwd = NULL;
|
||||
int rc;
|
||||
|
||||
(void)user;
|
||||
|
||||
pwd = getpwnam("bob");
|
||||
assert_non_null(pwd);
|
||||
|
||||
snprintf(bob_ssh_key, sizeof(bob_ssh_key), "%s/.ssh/id_ecdsa", pwd->pw_dir);
|
||||
|
||||
rc = ssh_pki_import_privkey_file(bob_ssh_key, NULL, NULL, NULL, &pkey);
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
|
||||
rc = ssh_userauth_publickey(jump_session, NULL, pkey);
|
||||
ssh_key_free(pkey);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void torture_proxyjump_multiple_jump(void **state)
|
||||
{
|
||||
struct torture_state *s = *state;
|
||||
@@ -129,11 +173,10 @@ static void torture_proxyjump_multiple_jump(void **state)
|
||||
const char *address = torture_server_address(AF_INET);
|
||||
int rc;
|
||||
socket_t fd;
|
||||
|
||||
struct ssh_jump_callbacks_struct c = {
|
||||
.before_connection = before_connection,
|
||||
.verify_knownhost = verify_knownhost,
|
||||
.authenticate = authenticate
|
||||
.authenticate = authenticate,
|
||||
};
|
||||
|
||||
rc = snprintf(proxyjump_buf,
|
||||
@@ -177,14 +220,14 @@ static void torture_proxyjump_multiple_sshd_jump(void **state)
|
||||
struct ssh_jump_callbacks_struct c = {
|
||||
.before_connection = before_connection,
|
||||
.verify_knownhost = verify_knownhost,
|
||||
.authenticate = authenticate,
|
||||
.authenticate = authenticate_doe,
|
||||
};
|
||||
|
||||
torture_setup_sshd_servers(state, false);
|
||||
|
||||
rc = snprintf(proxyjump_buf,
|
||||
sizeof(proxyjump_buf),
|
||||
"alice@%s:22,alice@%s:22",
|
||||
"doe@%s:22,doe@%s:22",
|
||||
address,
|
||||
address1);
|
||||
if (rc < 0 || rc >= (int)sizeof(proxyjump_buf)) {
|
||||
@@ -222,17 +265,22 @@ static void torture_proxyjump_multiple_sshd_users_jump(void **state)
|
||||
int rc;
|
||||
socket_t fd;
|
||||
|
||||
struct ssh_jump_callbacks_struct c = {
|
||||
struct ssh_jump_callbacks_struct c1 = {
|
||||
.before_connection = before_connection,
|
||||
.verify_knownhost = verify_knownhost,
|
||||
.authenticate = authenticate,
|
||||
.authenticate = authenticate_doe,
|
||||
};
|
||||
struct ssh_jump_callbacks_struct c2 = {
|
||||
.before_connection = before_connection,
|
||||
.verify_knownhost = verify_knownhost,
|
||||
.authenticate = authenticate_frank,
|
||||
};
|
||||
|
||||
torture_setup_sshd_servers(state, false);
|
||||
|
||||
rc = snprintf(proxyjump_buf,
|
||||
sizeof(proxyjump_buf),
|
||||
"doe@%s:22,alice@%s:22",
|
||||
"doe@%s:22,frank@%s:22",
|
||||
address,
|
||||
address1);
|
||||
if (rc < 0 || rc >= (int)sizeof(proxyjump_buf)) {
|
||||
@@ -240,9 +288,9 @@ static void torture_proxyjump_multiple_sshd_users_jump(void **state)
|
||||
}
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_PROXYJUMP, proxyjump_buf);
|
||||
assert_ssh_return_code(session, rc);
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_PROXYJUMP_CB_LIST_APPEND, &c);
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_PROXYJUMP_CB_LIST_APPEND, &c1);
|
||||
assert_ssh_return_code(session, rc);
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_PROXYJUMP_CB_LIST_APPEND, &c);
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_PROXYJUMP_CB_LIST_APPEND, &c2);
|
||||
assert_ssh_return_code(session, rc);
|
||||
|
||||
rc = ssh_connect(session);
|
||||
|
||||
@@ -2,6 +2,7 @@ bob:x:5000:9000:bob gecos:@HOMEDIR@/bob:/bin/sh
|
||||
alice:x:5001:9000:alice gecos:@HOMEDIR@/alice:/bin/sh
|
||||
charlie:x:5002:9000:charlie gecos:@HOMEDIR@/charlie:/bin/sh
|
||||
doe:x:5003:9000:doe gecos:@HOMEDIR@/doe:/bin/sh
|
||||
frank:x:5003:9000:doe gecos:@HOMEDIR@/frank:/bin/sh
|
||||
sshd:x:65530:65531:sshd:@HOMEDIR@:/sbin/nologin
|
||||
nobody:x:65533:65534:nobody gecos:@HOMEDIR@:/bin/false
|
||||
root:x:65534:65532:root gecos:@HOMEDIR@:/bin/false
|
||||
|
||||
@@ -28,6 +28,9 @@ if [ ! -d "$TESTDIR/db" ]; then
|
||||
directories.tokendir = $TESTDIR/db
|
||||
objectstore.backend = file
|
||||
log.level = DEBUG
|
||||
# # The hashed ECDSA mechanisms wrongly do not support multi-part operations
|
||||
# https://github.com/softhsm/SoftHSMv2/issues/842
|
||||
slots.mechanisms = -CKM_ECDSA_SHA1,CKM_ECDSA_SHA224,CKM_ECDSA_SHA256,CKM_ECDSA_SHA384,CKM_ECDSA_SHA512
|
||||
EOF
|
||||
|
||||
cat "$TESTDIR/softhsm.conf"
|
||||
|
||||
@@ -833,7 +833,7 @@ torture_setup_create_sshd_config(void **state, bool pam, bool second_sshd)
|
||||
"TrustedUserCAKeys %s\n"
|
||||
"\n"
|
||||
"LogLevel DEBUG3\n"
|
||||
"Subsystem sftp %s -l DEBUG2\n"
|
||||
"Subsystem sftp %s -l DEBUG3 -e\n"
|
||||
"\n"
|
||||
"PasswordAuthentication yes\n"
|
||||
"PubkeyAuthentication yes\n"
|
||||
@@ -873,7 +873,7 @@ torture_setup_create_sshd_config(void **state, bool pam, bool second_sshd)
|
||||
"TrustedUserCAKeys %s\n" /* Trusted CA */
|
||||
"\n"
|
||||
"LogLevel DEBUG3\n"
|
||||
"Subsystem sftp %s -l DEBUG2\n" /* SFTP server */
|
||||
"Subsystem sftp %s -l DEBUG3 -e\n" /* SFTP server */
|
||||
"\n"
|
||||
"PasswordAuthentication yes\n"
|
||||
"PubkeyAuthentication yes\n"
|
||||
|
||||
@@ -159,6 +159,8 @@ extern LIBSSH_THREAD int ssh_log_level;
|
||||
"\tProxyJump jumpbox:2222\n" \
|
||||
"Host two-step\n" \
|
||||
"\tProxyJump u1@first:222,u2@second:33\n" \
|
||||
"Host three-step\n" \
|
||||
"\tProxyJump u1@first:222,u2@second:33,u3@third:444\n" \
|
||||
"Host none\n" \
|
||||
"\tProxyJump none\n" \
|
||||
"Host only-command\n" \
|
||||
@@ -1172,6 +1174,23 @@ static void torture_config_proxyjump(void **state,
|
||||
"u1",
|
||||
"222");
|
||||
|
||||
/* Three step jump */
|
||||
torture_reset_config(session);
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "three-step");
|
||||
_parse_config(session, file, string, SSH_OK);
|
||||
helper_proxy_jump_check(session->opts.proxy_jumps->root,
|
||||
"third",
|
||||
"u3",
|
||||
"444");
|
||||
helper_proxy_jump_check(session->opts.proxy_jumps->root->next,
|
||||
"second",
|
||||
"u2",
|
||||
"33");
|
||||
helper_proxy_jump_check(session->opts.proxy_jumps->root->next->next,
|
||||
"first",
|
||||
"u1",
|
||||
"222");
|
||||
|
||||
/* none */
|
||||
torture_reset_config(session);
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "none");
|
||||
@@ -1237,6 +1256,13 @@ static void torture_config_proxyjump(void **state,
|
||||
assert_string_equal(session->opts.ProxyCommand,
|
||||
"ssh -l u1 -p 222 -J u2@second:33 -W '[%h]:%p' first");
|
||||
|
||||
/* Three step jump */
|
||||
torture_reset_config(session);
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "three-step");
|
||||
_parse_config(session, file, string, SSH_OK);
|
||||
assert_string_equal(session->opts.ProxyCommand,
|
||||
"ssh -l u1 -p 222 -J u2@second:33,u3@third:444 -W '[%h]:%p' first");
|
||||
|
||||
/* none */
|
||||
torture_reset_config(session);
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "none");
|
||||
|
||||
@@ -696,6 +696,82 @@ static void torture_knownhosts_algorithms_global(void **state)
|
||||
ssh_free(session);
|
||||
}
|
||||
|
||||
static int setup_bad_knownhosts_file(void **state)
|
||||
{
|
||||
char *tmp_file = NULL;
|
||||
size_t nwritten;
|
||||
FILE *fp = NULL;
|
||||
int rc = 0;
|
||||
|
||||
tmp_file = torture_create_temp_file(TMP_FILE_NAME);
|
||||
assert_non_null(tmp_file);
|
||||
|
||||
*state = tmp_file;
|
||||
|
||||
fp = fopen(tmp_file, "w");
|
||||
assert_non_null(fp);
|
||||
|
||||
nwritten = fwrite(LOCALHOST_DEFAULT_ED25519,
|
||||
sizeof(char),
|
||||
strlen(LOCALHOST_DEFAULT_ED25519),
|
||||
fp);
|
||||
if (nwritten != strlen(LOCALHOST_DEFAULT_ED25519)) {
|
||||
rc = -1;
|
||||
goto close_fp;
|
||||
}
|
||||
|
||||
nwritten = fwrite("\n", sizeof(char), 1, fp);
|
||||
if (nwritten != 1) {
|
||||
rc = -1;
|
||||
goto close_fp;
|
||||
}
|
||||
|
||||
#define LOCALHOST_BAD_LINE "localhost \n"
|
||||
nwritten = fwrite(LOCALHOST_BAD_LINE,
|
||||
sizeof(char),
|
||||
strlen(LOCALHOST_BAD_LINE),
|
||||
fp);
|
||||
if (nwritten != strlen(LOCALHOST_BAD_LINE)) {
|
||||
rc = -1;
|
||||
goto close_fp;
|
||||
}
|
||||
|
||||
close_fp:
|
||||
fclose(fp);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void torture_knownhosts_has_entry(void **state)
|
||||
{
|
||||
const char *knownhosts_file = *state;
|
||||
enum ssh_known_hosts_e found;
|
||||
ssh_session session;
|
||||
bool process_config = false;
|
||||
struct ssh_knownhosts_entry *entry = NULL;
|
||||
|
||||
session = ssh_new();
|
||||
assert_non_null(session);
|
||||
|
||||
/* This makes sure the global configuration file is not processed */
|
||||
ssh_options_set(session, SSH_OPTIONS_PROCESS_CONFIG, &process_config);
|
||||
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
|
||||
/* This makes sure the current-user's known hosts are not used */
|
||||
ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, "/dev/null");
|
||||
ssh_options_set(session, SSH_OPTIONS_GLOBAL_KNOWNHOSTS, knownhosts_file);
|
||||
|
||||
/* Error is expected -- this tests the memory is not leaked from this
|
||||
* test case */
|
||||
found = ssh_session_has_known_hosts_entry(session);
|
||||
assert_int_equal(found, SSH_KNOWN_HOSTS_ERROR);
|
||||
|
||||
found = ssh_session_get_known_hosts_entry(session, &entry);
|
||||
assert_int_equal(found, SSH_KNOWN_HOSTS_ERROR);
|
||||
assert_null(entry);
|
||||
|
||||
ssh_free(session);
|
||||
}
|
||||
#endif /* _WIN32 There is no /dev/null on Windows */
|
||||
|
||||
int torture_run_tests(void) {
|
||||
@@ -738,6 +814,9 @@ int torture_run_tests(void) {
|
||||
cmocka_unit_test_setup_teardown(torture_knownhosts_algorithms_global,
|
||||
setup_knownhosts_file,
|
||||
teardown_knownhosts_file),
|
||||
cmocka_unit_test_setup_teardown(torture_knownhosts_has_entry,
|
||||
setup_bad_knownhosts_file,
|
||||
teardown_knownhosts_file),
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user