mirror of
https://git.libssh.org/projects/libssh.git
synced 2026-03-24 20:40:09 +09:00
Compare commits
6 Commits
a05b2b76be
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
729a44e121 | ||
|
|
051ac812db | ||
|
|
01772c4f79 | ||
|
|
9f7c596ca5 | ||
|
|
34bbb48561 | ||
|
|
f060583d6f |
@@ -784,8 +784,6 @@ coverity:
|
||||
- mkdir obj && cd obj
|
||||
only:
|
||||
- branches@libssh/libssh-mirror
|
||||
- branches@cryptomilk/libssh-mirror
|
||||
- branches@jjelen/libssh-mirror
|
||||
|
||||
# TODO add -DFUZZ_TESTING=ON clang cant find _LLVMFuzzerInitialize on arm64
|
||||
macos-m1:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* This is a sample implementation of a libssh based SSH server */
|
||||
/* This is a sample implementation of a libssh based SFTP server */
|
||||
/*
|
||||
Copyright 2014 Audrius Butkevicius
|
||||
|
||||
@@ -9,6 +9,28 @@ domain. This does not apply to the rest of the library though, but it is
|
||||
allowed to cut-and-paste working code from this file to any license of
|
||||
program.
|
||||
The goal is to show the API in action.
|
||||
|
||||
!!! WARNING / ACHTUNG !!!
|
||||
|
||||
This is not a production-ready SFTP server implementation. While it demonstrates
|
||||
how an SFTP server can be implemented on the SFTP layer and integrated into
|
||||
existing SSH server, it lacks many steps int the authentication and
|
||||
session establishment!
|
||||
|
||||
It allows to log in any user with hardcoded credentials below or with public
|
||||
key provided from authorized keys file.
|
||||
|
||||
The resulting SFTP session keeps running under original user who runs the
|
||||
example server and therefore the SFTP session has access to all files that are
|
||||
accessible to the user running the server.
|
||||
|
||||
Real-world servers should at very least switch the user to unprivileged one
|
||||
after authentication using setuid(). If some more restrictions are needed,
|
||||
generally limiting what files should and should not be accessible, it is
|
||||
recommended to use chroot() as handling symlinks can be tricky in the SFTP
|
||||
callbacks.
|
||||
|
||||
!!! WARNING / ACHTUNG !!!
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
@@ -10,6 +10,23 @@ allowed to cut-and-paste working code from this file to any license of
|
||||
program.
|
||||
The goal is to show the API in action. It's not a reference on how terminal
|
||||
clients must be made or how a client should react.
|
||||
|
||||
!!! WARNING / ACHTUNG !!!
|
||||
|
||||
This is not a production-ready SSH server implementation. While it demonstrates
|
||||
how an SSH server can be implemented, it lacks many steps during
|
||||
the authentication and session establishment!
|
||||
|
||||
It allows to log in any user with hardcoded credentials below or with public
|
||||
key provided from authorized keys file.
|
||||
|
||||
The resulting session keeps running under original user who runs the example
|
||||
server and therefore it retains the same permissions.
|
||||
|
||||
Real-world servers should at very least switch the user to unprivileged one
|
||||
after authentication using setuid().
|
||||
|
||||
!!! WARNING / ACHTUNG !!!
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
@@ -9,6 +9,23 @@ domain. This does not apply to the rest of the library though, but it is
|
||||
allowed to cut-and-paste working code from this file to any license of
|
||||
program.
|
||||
The goal is to show the API in action.
|
||||
|
||||
!!! WARNING / ACHTUNG !!!
|
||||
|
||||
This is not a production-ready SSH server implementation. While it demonstrates
|
||||
how an SSH server can be implemented, it lacks many steps during
|
||||
the authentication and session establishment!
|
||||
|
||||
It allows to log in any user with hardcoded credentials below or with public
|
||||
key provided from authorized keys file.
|
||||
|
||||
The resulting session keeps running under original user who runs the example
|
||||
server and therefore it retains the same permissions.
|
||||
|
||||
Real-world servers should at very least switch the user to unprivileged one
|
||||
after authentication using setuid().
|
||||
|
||||
!!! WARNING / ACHTUNG !!!
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
@@ -130,14 +130,15 @@ extern "C" {
|
||||
/* SSH Key Functions */
|
||||
void ssh_key_clean (ssh_key key);
|
||||
|
||||
const char *
|
||||
ssh_key_get_signature_algorithm(ssh_session session,
|
||||
enum ssh_keytypes_e type);
|
||||
enum ssh_keytypes_e ssh_key_type_from_signature_name(const char *name);
|
||||
const char *ssh_key_get_signature_algorithm(ssh_session session,
|
||||
enum ssh_keytypes_e type);
|
||||
enum ssh_keytypes_e ssh_key_type_plain(enum ssh_keytypes_e type);
|
||||
enum ssh_digest_e ssh_key_type_to_hash(ssh_session session,
|
||||
enum ssh_keytypes_e type);
|
||||
enum ssh_digest_e ssh_key_hash_from_name(const char *name);
|
||||
|
||||
int ssh_key_type_and_hash_from_signature_name(const char *name,
|
||||
enum ssh_keytypes_e *type,
|
||||
enum ssh_digest_e *hash_type);
|
||||
|
||||
#define is_ecdsa_key_type(t) \
|
||||
((t) >= SSH_KEYTYPE_ECDSA_P256 && (t) <= SSH_KEYTYPE_ECDSA_P521)
|
||||
|
||||
@@ -1738,7 +1738,7 @@ int ssh_channel_write(ssh_channel channel, const void *data, uint32_t len)
|
||||
*/
|
||||
int ssh_channel_is_open(ssh_channel channel)
|
||||
{
|
||||
if (channel == NULL) {
|
||||
if (channel == NULL || channel->session == NULL) {
|
||||
return 0;
|
||||
}
|
||||
return (channel->state == SSH_CHANNEL_STATE_OPEN && channel->session->alive != 0);
|
||||
|
||||
180
src/pki.c
180
src/pki.c
@@ -449,40 +449,137 @@ const char *ssh_key_type_to_char(enum ssh_keytypes_e type) {
|
||||
/* We should never reach this */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
enum ssh_digest_e ssh_key_hash_from_name(const char *name)
|
||||
/**
|
||||
* @brief Convert a signature algorithm name to a key type and hash type.
|
||||
*
|
||||
* Looks up the given signature algorithm name and returns both the
|
||||
* corresponding key type and digest algorithm in a single call,
|
||||
* avoiding double string comparisons on the same input.
|
||||
*
|
||||
* @param[in] name The signature algorithm name to convert (e.g.
|
||||
* "ssh-rsa", "rsa-sha2-256", "ecdsa-sha2-nistp256").
|
||||
*
|
||||
* @param[out] type A pointer to store the resulting key type.
|
||||
*
|
||||
* @param[out] hash_type A pointer to store the resulting hash/digest type.
|
||||
*
|
||||
* @return SSH_OK on success, SSH_ERROR if name is NULL or
|
||||
* unknown.
|
||||
*/
|
||||
int ssh_key_type_and_hash_from_signature_name(const char *name,
|
||||
enum ssh_keytypes_e *type,
|
||||
enum ssh_digest_e *hash_type)
|
||||
{
|
||||
if (name == NULL) {
|
||||
/* TODO we should rather fail */
|
||||
return SSH_DIGEST_AUTO;
|
||||
size_t len;
|
||||
|
||||
if (name == NULL || type == NULL || hash_type == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (strcmp(name, "ssh-rsa") == 0) {
|
||||
return SSH_DIGEST_SHA1;
|
||||
} else if (strcmp(name, "rsa-sha2-256") == 0) {
|
||||
return SSH_DIGEST_SHA256;
|
||||
} else if (strcmp(name, "rsa-sha2-512") == 0) {
|
||||
return SSH_DIGEST_SHA512;
|
||||
} else if (strcmp(name, "ecdsa-sha2-nistp256") == 0) {
|
||||
return SSH_DIGEST_SHA256;
|
||||
} else if (strcmp(name, "ecdsa-sha2-nistp384") == 0) {
|
||||
return SSH_DIGEST_SHA384;
|
||||
} else if (strcmp(name, "ecdsa-sha2-nistp521") == 0) {
|
||||
return SSH_DIGEST_SHA512;
|
||||
} else if (strcmp(name, "ssh-ed25519") == 0) {
|
||||
return SSH_DIGEST_AUTO;
|
||||
} else if (strcmp(name, "sk-ecdsa-sha2-nistp256@openssh.com") == 0) {
|
||||
return SSH_DIGEST_SHA256;
|
||||
} else if (strcmp(name, "sk-ssh-ed25519@openssh.com") == 0) {
|
||||
return SSH_DIGEST_AUTO;
|
||||
len = strlen(name);
|
||||
|
||||
if (len == 7 && strcmp(name, "ssh-rsa") == 0) {
|
||||
*type = SSH_KEYTYPE_RSA;
|
||||
*hash_type = SSH_DIGEST_SHA1;
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
if (len == 11 && strcmp(name, "ssh-ed25519") == 0) {
|
||||
*type = SSH_KEYTYPE_ED25519;
|
||||
*hash_type = SSH_DIGEST_AUTO;
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
if (len == 12) {
|
||||
if (strcmp(name, "rsa-sha2-256") == 0) {
|
||||
*type = SSH_KEYTYPE_RSA;
|
||||
*hash_type = SSH_DIGEST_SHA256;
|
||||
return SSH_OK;
|
||||
}
|
||||
if (strcmp(name, "rsa-sha2-512") == 0) {
|
||||
*type = SSH_KEYTYPE_RSA;
|
||||
*hash_type = SSH_DIGEST_SHA512;
|
||||
return SSH_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (len == 19) {
|
||||
if (strcmp(name, "ecdsa-sha2-nistp256") == 0) {
|
||||
*type = SSH_KEYTYPE_ECDSA_P256;
|
||||
*hash_type = SSH_DIGEST_SHA256;
|
||||
return SSH_OK;
|
||||
}
|
||||
if (strcmp(name, "ecdsa-sha2-nistp384") == 0) {
|
||||
*type = SSH_KEYTYPE_ECDSA_P384;
|
||||
*hash_type = SSH_DIGEST_SHA384;
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
if (strcmp(name, "ecdsa-sha2-nistp521") == 0) {
|
||||
*type = SSH_KEYTYPE_ECDSA_P521;
|
||||
*hash_type = SSH_DIGEST_SHA512;
|
||||
return SSH_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (len == 26 && strcmp(name, "sk-ssh-ed25519@openssh.com") == 0) {
|
||||
*type = SSH_KEYTYPE_SK_ED25519;
|
||||
*hash_type = SSH_DIGEST_AUTO;
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
if (len == 28 && strcmp(name, "ssh-rsa-cert-v01@openssh.com") == 0) {
|
||||
*type = SSH_KEYTYPE_RSA_CERT01;
|
||||
*hash_type = SSH_DIGEST_SHA1;
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
if (len == 32 && strcmp(name, "ssh-ed25519-cert-v01@openssh.com") == 0) {
|
||||
*type = SSH_KEYTYPE_ED25519_CERT01;
|
||||
*hash_type = SSH_DIGEST_AUTO;
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
if (len == 33) {
|
||||
if (strcmp(name, "rsa-sha2-256-cert-v01@openssh.com") == 0) {
|
||||
*type = SSH_KEYTYPE_RSA_CERT01;
|
||||
*hash_type = SSH_DIGEST_SHA256;
|
||||
return SSH_OK;
|
||||
}
|
||||
if (strcmp(name, "rsa-sha2-512-cert-v01@openssh.com") == 0) {
|
||||
*type = SSH_KEYTYPE_RSA_CERT01;
|
||||
*hash_type = SSH_DIGEST_SHA512;
|
||||
return SSH_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (len == 34 && strcmp(name, "sk-ecdsa-sha2-nistp256@openssh.com") == 0) {
|
||||
*type = SSH_KEYTYPE_SK_ECDSA;
|
||||
*hash_type = SSH_DIGEST_SHA256;
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
if (len == 40) {
|
||||
if (strcmp(name, "ecdsa-sha2-nistp256-cert-v01@openssh.com") == 0) {
|
||||
*type = SSH_KEYTYPE_ECDSA_P256_CERT01;
|
||||
*hash_type = SSH_DIGEST_SHA256;
|
||||
return SSH_OK;
|
||||
}
|
||||
if (strcmp(name, "ecdsa-sha2-nistp384-cert-v01@openssh.com") == 0) {
|
||||
*type = SSH_KEYTYPE_ECDSA_P384_CERT01;
|
||||
*hash_type = SSH_DIGEST_SHA384;
|
||||
return SSH_OK;
|
||||
}
|
||||
if (strcmp(name, "ecdsa-sha2-nistp521-cert-v01@openssh.com") == 0) {
|
||||
*type = SSH_KEYTYPE_ECDSA_P521_CERT01;
|
||||
*hash_type = SSH_DIGEST_SHA512;
|
||||
return SSH_OK;
|
||||
}
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_TRACE, "Unknown signature name %s", name);
|
||||
|
||||
/* TODO we should rather fail */
|
||||
return SSH_DIGEST_AUTO;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks the given key against the configured allowed
|
||||
* public key algorithm types
|
||||
@@ -700,27 +797,6 @@ ssh_key_get_signature_algorithm(ssh_session session,
|
||||
return ssh_key_signature_to_char(type, hash_type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert a ssh key algorithm name to a ssh key algorithm type.
|
||||
*
|
||||
* @param[in] name The name to convert.
|
||||
*
|
||||
* @return The enum ssh key algorithm type.
|
||||
*/
|
||||
enum ssh_keytypes_e ssh_key_type_from_signature_name(const char *name) {
|
||||
if (name == NULL) {
|
||||
return SSH_KEYTYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
if ((strcmp(name, "rsa-sha2-256") == 0) ||
|
||||
(strcmp(name, "rsa-sha2-512") == 0)) {
|
||||
return SSH_KEYTYPE_RSA;
|
||||
}
|
||||
|
||||
/* Otherwise the key type matches the signature type */
|
||||
return ssh_key_type_from_name(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert a ssh key name to a ssh key type.
|
||||
*
|
||||
@@ -2899,8 +2975,12 @@ int ssh_pki_import_signature_blob(const ssh_string sig_blob,
|
||||
}
|
||||
|
||||
alg = ssh_string_get_char(algorithm);
|
||||
type = ssh_key_type_from_signature_name(alg);
|
||||
hash_type = ssh_key_hash_from_name(alg);
|
||||
rc = ssh_key_type_and_hash_from_signature_name(alg, &type, &hash_type);
|
||||
if (rc != SSH_OK) {
|
||||
SSH_BUFFER_FREE(buf);
|
||||
SSH_STRING_FREE(algorithm);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
SSH_STRING_FREE(algorithm);
|
||||
|
||||
blob = ssh_buffer_get_ssh_string(buf);
|
||||
|
||||
@@ -437,6 +437,7 @@ int crypt_set_algorithms_server(ssh_session session){
|
||||
struct ssh_cipher_struct *ssh_ciphertab=ssh_get_ciphertab();
|
||||
struct ssh_hmac_struct *ssh_hmactab=ssh_get_hmactab();
|
||||
int cmp;
|
||||
int rc;
|
||||
|
||||
if (session == NULL) {
|
||||
return SSH_ERROR;
|
||||
@@ -580,8 +581,24 @@ int crypt_set_algorithms_server(ssh_session session){
|
||||
}
|
||||
|
||||
method = session->next_crypto->kex_methods[SSH_HOSTKEYS];
|
||||
session->srv.hostkey = ssh_key_type_from_signature_name(method);
|
||||
session->srv.hostkey_digest = ssh_key_hash_from_name(method);
|
||||
|
||||
/* For GSSAPI key exchange, hostkey algorithm may be "null" */
|
||||
if (strcmp(method, "null") == 0) {
|
||||
session->srv.hostkey = SSH_KEYTYPE_UNKNOWN;
|
||||
session->srv.hostkey_digest = SSH_DIGEST_AUTO;
|
||||
} else {
|
||||
rc = ssh_key_type_and_hash_from_signature_name(
|
||||
method,
|
||||
&session->srv.hostkey,
|
||||
&session->srv.hostkey_digest);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"unknown hostkey algorithm %s",
|
||||
method);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* setup DH key exchange type */
|
||||
switch (session->next_crypto->kex_type) {
|
||||
|
||||
@@ -13,6 +13,9 @@ macro(fuzzer name)
|
||||
target_sources(${name} PRIVATE $<TARGET_OBJECTS:ssh_server_mock_obj>)
|
||||
target_link_libraries(${name} PRIVATE pthread)
|
||||
endif()
|
||||
if (WITH_COVERAGE)
|
||||
append_coverage_compiler_flags_to_target(${name})
|
||||
endif (WITH_COVERAGE)
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
set_target_properties(${name}
|
||||
|
||||
@@ -39,10 +39,29 @@ static void torture_channel_select(void **state)
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void torture_channel_null_session(void **state)
|
||||
{
|
||||
ssh_channel channel = NULL;
|
||||
|
||||
(void)state;
|
||||
|
||||
channel = calloc(1, sizeof(struct ssh_channel_struct));
|
||||
|
||||
assert_non_null(channel);
|
||||
|
||||
channel->state = SSH_CHANNEL_STATE_OPEN;
|
||||
channel->session = NULL;
|
||||
|
||||
assert_int_equal(ssh_channel_is_open(channel), 0);
|
||||
|
||||
free(channel);
|
||||
}
|
||||
|
||||
int torture_run_tests(void) {
|
||||
int rc;
|
||||
struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test(torture_channel_select),
|
||||
cmocka_unit_test(torture_channel_null_session),
|
||||
};
|
||||
|
||||
ssh_init();
|
||||
|
||||
@@ -107,6 +107,76 @@ static void torture_pki_signature(void **state)
|
||||
ssh_signature_free(sig);
|
||||
}
|
||||
|
||||
static void torture_pki_type_and_hash_from_signature_name(void **state)
|
||||
{
|
||||
enum ssh_keytypes_e type;
|
||||
enum ssh_digest_e hash_type;
|
||||
int rc;
|
||||
|
||||
(void)state; /* unused */
|
||||
|
||||
/* Test NULL input */
|
||||
rc = ssh_key_type_and_hash_from_signature_name(NULL, &type, &hash_type);
|
||||
assert_int_equal(rc, SSH_ERROR);
|
||||
|
||||
/* Test NULL output pointers */
|
||||
rc = ssh_key_type_and_hash_from_signature_name("ssh-rsa", NULL, &hash_type);
|
||||
assert_int_equal(rc, SSH_ERROR);
|
||||
|
||||
rc = ssh_key_type_and_hash_from_signature_name("ssh-rsa", &type, NULL);
|
||||
assert_int_equal(rc, SSH_ERROR);
|
||||
|
||||
/* Test unknown name */
|
||||
rc = ssh_key_type_and_hash_from_signature_name("unknown-algo",
|
||||
&type,
|
||||
&hash_type);
|
||||
assert_int_equal(rc, SSH_ERROR);
|
||||
|
||||
/* Test valid RSA signatures */
|
||||
rc =
|
||||
ssh_key_type_and_hash_from_signature_name("ssh-rsa", &type, &hash_type);
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
assert_int_equal(type, SSH_KEYTYPE_RSA);
|
||||
assert_int_equal(hash_type, SSH_DIGEST_SHA1);
|
||||
|
||||
rc = ssh_key_type_and_hash_from_signature_name("rsa-sha2-256",
|
||||
&type,
|
||||
&hash_type);
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
assert_int_equal(type, SSH_KEYTYPE_RSA);
|
||||
assert_int_equal(hash_type, SSH_DIGEST_SHA256);
|
||||
|
||||
rc = ssh_key_type_and_hash_from_signature_name("rsa-sha2-512",
|
||||
&type,
|
||||
&hash_type);
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
assert_int_equal(type, SSH_KEYTYPE_RSA);
|
||||
assert_int_equal(hash_type, SSH_DIGEST_SHA512);
|
||||
|
||||
/* Test valid ECDSA signatures */
|
||||
rc = ssh_key_type_and_hash_from_signature_name("ecdsa-sha2-nistp256",
|
||||
&type,
|
||||
&hash_type);
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
assert_int_equal(type, SSH_KEYTYPE_ECDSA_P256);
|
||||
assert_int_equal(hash_type, SSH_DIGEST_SHA256);
|
||||
|
||||
/* Test valid ED25519 signature */
|
||||
rc = ssh_key_type_and_hash_from_signature_name("ssh-ed25519",
|
||||
&type,
|
||||
&hash_type);
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
assert_int_equal(type, SSH_KEYTYPE_ED25519);
|
||||
assert_int_equal(hash_type, SSH_DIGEST_AUTO);
|
||||
|
||||
/* Test that loose key names are rejected */
|
||||
rc = ssh_key_type_and_hash_from_signature_name("ecdsa", &type, &hash_type);
|
||||
assert_int_equal(rc, SSH_ERROR);
|
||||
|
||||
rc = ssh_key_type_and_hash_from_signature_name("rsa", &type, &hash_type);
|
||||
assert_int_equal(rc, SSH_ERROR);
|
||||
}
|
||||
|
||||
struct key_attrs {
|
||||
int sign;
|
||||
int verify;
|
||||
@@ -415,6 +485,7 @@ int torture_run_tests(void) {
|
||||
struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test(torture_pki_keytype),
|
||||
cmocka_unit_test(torture_pki_signature),
|
||||
cmocka_unit_test(torture_pki_type_and_hash_from_signature_name),
|
||||
cmocka_unit_test_setup_teardown(torture_pki_verify_mismatch,
|
||||
setup_cert_dir,
|
||||
teardown_cert_dir),
|
||||
|
||||
Reference in New Issue
Block a user