Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions include/libssh/libssh.h
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,7 @@ enum ssh_options_e {
SSH_OPTIONS_PROCESS_CONFIG,
SSH_OPTIONS_REKEY_DATA,
SSH_OPTIONS_REKEY_TIME,
SSH_OPTIONS_OWNS_SOCKET,
};

enum {
Expand Down Expand Up @@ -653,6 +654,7 @@ LIBSSH_API int ssh_key_is_private(const ssh_key k);
LIBSSH_API int ssh_key_cmp(const ssh_key k1,
const ssh_key k2,
enum ssh_keycmp_e what);
LIBSSH_API ssh_key ssh_key_dup(const ssh_key key);

LIBSSH_API int ssh_pki_generate(enum ssh_keytypes_e type, int parameter,
ssh_key *pkey);
Expand Down Expand Up @@ -822,6 +824,9 @@ LIBSSH_API uint32_t ssh_buffer_get_data(ssh_buffer buffer, void *data, uint32_t
LIBSSH_API void *ssh_buffer_get(ssh_buffer buffer);
LIBSSH_API uint32_t ssh_buffer_get_len(ssh_buffer buffer);

LIBSSH_API int pki_sign_string(ssh_key privkey, ssh_string input, ssh_string* output);
LIBSSH_API int pki_verify_string(ssh_key pubkey, ssh_string sig_blob, ssh_string input);

#ifndef LIBSSH_LEGACY_0_4
#include "libssh/legacy.h"
#endif
Expand Down
2 changes: 1 addition & 1 deletion include/libssh/pki.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@ struct ssh_signature_struct {
typedef struct ssh_signature_struct *ssh_signature;

/* SSH Key Functions */
ssh_key ssh_key_dup(const ssh_key key);
void ssh_key_clean (ssh_key key);

const char *
Expand All @@ -111,6 +110,7 @@ enum ssh_keytypes_e ssh_key_type_from_signature_name(const char *name);
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 key_type_to_hash(enum ssh_keytypes_e type);
enum ssh_digest_e ssh_key_hash_from_name(const char *name);

#define is_ecdsa_key_type(t) \
Expand Down
1 change: 1 addition & 0 deletions include/libssh/session.h
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ struct ssh_session_struct {
uint8_t options_seen[SOC_MAX];
uint64_t rekey_data;
uint32_t rekey_time;
bool owns_socket;
} opts;
/* counters */
ssh_counter socket_counter;
Expand Down
1 change: 1 addition & 0 deletions include/libssh/socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ ssh_socket ssh_socket_new(ssh_session session);
void ssh_socket_reset(ssh_socket s);
void ssh_socket_free(ssh_socket s);
void ssh_socket_set_fd(ssh_socket s, socket_t fd);
int ssh_socket_owns_fd(ssh_socket s);
socket_t ssh_socket_get_fd(ssh_socket s);
#ifndef _WIN32
int ssh_socket_unix(ssh_socket s, const char *path);
Expand Down
9 changes: 9 additions & 0 deletions src/options.c
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,15 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
}

switch (type) {
case SSH_OPTIONS_OWNS_SOCKET:
if (value == NULL) {
ssh_set_error_invalid(session);
return -1;
} else {
bool *x = (bool *)value;
session->opts.owns_socket = *x;
}
break;
case SSH_OPTIONS_HOST:
v = value;
if (v == NULL || v[0] == '\0') {
Expand Down
80 changes: 80 additions & 0 deletions src/pki.c
Original file line number Diff line number Diff line change
Expand Up @@ -2304,6 +2304,86 @@ ssh_signature pki_do_sign(const ssh_key privkey,
return pki_sign_data(privkey, hash_type, input, input_len);
}

enum ssh_digest_e key_type_to_hash(enum ssh_keytypes_e type)
{
switch (type) {
case SSH_KEYTYPE_DSS_CERT01:
case SSH_KEYTYPE_DSS:
return SSH_DIGEST_SHA1;
case SSH_KEYTYPE_RSA_CERT01:
case SSH_KEYTYPE_RSA:
return SSH_DIGEST_SHA512;
case SSH_KEYTYPE_ECDSA_P256_CERT01:
case SSH_KEYTYPE_ECDSA_P256:
return SSH_DIGEST_SHA256;
case SSH_KEYTYPE_ECDSA_P384_CERT01:
case SSH_KEYTYPE_ECDSA_P384:
return SSH_DIGEST_SHA384;
case SSH_KEYTYPE_ECDSA_P521_CERT01:
case SSH_KEYTYPE_ECDSA_P521:
return SSH_DIGEST_SHA512;
case SSH_KEYTYPE_ED25519_CERT01:
case SSH_KEYTYPE_ED25519:
return SSH_DIGEST_AUTO;
case SSH_KEYTYPE_RSA1:
case SSH_KEYTYPE_ECDSA:
case SSH_KEYTYPE_UNKNOWN:
default:
SSH_LOG(SSH_LOG_WARN, "Digest algorithm to be used with key type %u "
"is not defined", type);
}

/* We should never reach this */
return SSH_DIGEST_AUTO;
}

int pki_sign_string(ssh_key privkey, ssh_string input, ssh_string* output)
{
enum ssh_digest_e hash_type = key_type_to_hash(privkey->type);
int rc;
ssh_signature sig = pki_do_sign(privkey, ssh_string_data(input), ssh_string_len(input), hash_type);
if (sig == NULL) {
return SSH_ERROR;
}
rc = ssh_pki_export_signature_blob(sig, output);
ssh_signature_free(sig);
return rc;
}

int pki_verify_string(ssh_key pubkey, ssh_string sig_blob, ssh_string input)
{
int rc;
ssh_signature sig;
rc = ssh_pki_import_signature_blob(sig_blob, pubkey, &sig);
if (rc != SSH_OK) {
return rc;
}
SSH_LOG(SSH_LOG_FUNCTIONS,
"Going to verify a %s type signature",
sig->type_c);

if (pubkey->type != sig->type) {
SSH_LOG(SSH_LOG_WARN,
"Can not verify %s signature with %s key",
sig->type_c, pubkey->type_c);
rc = SSH_ERROR;
goto end;
}

/* Check if public key and hash type are compatible */
rc = pki_key_check_hash_compatible(pubkey, sig->hash_type);
if (rc != SSH_OK) {
rc = SSH_ERROR;
goto end;
}

rc = pki_verify_data_signature(sig, pubkey, ssh_string_data(input), ssh_string_len(input));
end:
ssh_signature_free(sig);
return rc;

}

/*
* This function signs the session id as a string then
* the content of sigbuf */
Expand Down
11 changes: 8 additions & 3 deletions src/pki_crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -1373,7 +1373,7 @@ ssh_string pki_publickey_to_blob(const ssh_key key)

return NULL;
}

#ifdef HAVE_DSA
static ssh_string pki_dsa_signature_to_blob(const ssh_signature sig)
{
char buffer[40] = { 0 };
Expand Down Expand Up @@ -1459,6 +1459,7 @@ static ssh_string pki_dsa_signature_to_blob(const ssh_signature sig)
SSH_STRING_FREE(s);
return NULL;
}
#endif

static ssh_string pki_ecdsa_signature_to_blob(const ssh_signature sig)
{
Expand Down Expand Up @@ -1552,9 +1553,11 @@ ssh_string pki_signature_to_blob(const ssh_signature sig)
ssh_string sig_blob = NULL;

switch(sig->type) {
#ifdef HAVE_DSA
case SSH_KEYTYPE_DSS:
sig_blob = pki_dsa_signature_to_blob(sig);
break;
#endif
case SSH_KEYTYPE_RSA:
case SSH_KEYTYPE_RSA1:
sig_blob = ssh_string_copy(sig->raw_sig);
Expand Down Expand Up @@ -1646,7 +1649,7 @@ static int pki_signature_from_rsa_blob(const ssh_key pubkey,
SSH_STRING_FREE(sig_blob_padded);
return SSH_ERROR;
}

#ifdef HAVE_DSA
static int pki_signature_from_dsa_blob(UNUSED_PARAM(const ssh_key pubkey),
const ssh_string sig_blob,
ssh_signature sig)
Expand Down Expand Up @@ -1773,7 +1776,7 @@ static int pki_signature_from_dsa_blob(UNUSED_PARAM(const ssh_key pubkey),
DSA_SIG_free(dsa_sig);
return SSH_ERROR;
}

#endif
static int pki_signature_from_ecdsa_blob(UNUSED_PARAM(const ssh_key pubkey),
const ssh_string sig_blob,
ssh_signature sig)
Expand Down Expand Up @@ -1938,12 +1941,14 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
sig->hash_type = hash_type;

switch(type) {
#ifdef HAVE_DSA
case SSH_KEYTYPE_DSS:
rc = pki_signature_from_dsa_blob(pubkey, sig_blob, sig);
if (rc != SSH_OK) {
goto error;
}
break;
#endif
case SSH_KEYTYPE_RSA:
case SSH_KEYTYPE_RSA1:
rc = pki_signature_from_rsa_blob(pubkey, sig_blob, sig);
Expand Down
3 changes: 2 additions & 1 deletion src/session.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ ssh_session ssh_new(void)
session->opts.StrictHostKeyChecking = 1;
session->opts.port = 0;
session->opts.fd = -1;
session->opts.owns_socket = true;
session->opts.compressionlevel = 7;
session->opts.nodelay = 0;

Expand Down Expand Up @@ -1039,7 +1040,7 @@ int ssh_get_pubkey_hash(ssh_session session, unsigned char **hash)
/**
* @brief Deallocate the hash obtained by ssh_get_pubkey_hash.
*
* This is required under Microsoft platform as this library might use a
* This is required under Microsoft platform as this library might use a
* different C library than your software, hence a different heap.
*
* @param[in] hash The buffer to deallocate.
Expand Down
16 changes: 13 additions & 3 deletions src/socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ enum ssh_socket_states_e {
struct ssh_socket_struct {
socket_t fd;
int fd_is_socket;
int owns_fd;
int last_errno;
int read_wontblock; /* reading now on socket will
not block */
Expand Down Expand Up @@ -155,6 +156,10 @@ ssh_socket ssh_socket_new(ssh_session session)
return NULL;
}
s->fd = SSH_INVALID_SOCKET;
if (session->opts.owns_socket)
s->owns_fd = 1;
else
s->owns_fd = 0;
s->last_errno = -1;
s->fd_is_socket = 1;
s->session = session;
Expand Down Expand Up @@ -446,7 +451,7 @@ int ssh_socket_unix(ssh_socket s, const char *path)
*/
void ssh_socket_close(ssh_socket s)
{
if (ssh_socket_is_open(s)) {
if (ssh_socket_is_open(s) && ssh_socket_owns_fd(s)) {
#ifdef _WIN32
CLOSE_SOCKET(s->fd);
s->last_errno = WSAGetLastError();
Expand Down Expand Up @@ -511,6 +516,11 @@ void ssh_socket_set_fd(ssh_socket s, socket_t fd)
}
}

int ssh_socket_owns_fd(ssh_socket s)
{
return s->owns_fd;
}

/** \internal
* \brief returns the input file descriptor of the socket
*/
Expand Down Expand Up @@ -842,7 +852,7 @@ int ssh_socket_connect(ssh_socket s,
const char *bind_addr)
{
socket_t fd;

if (s->state != SSH_SOCKET_NONE) {
ssh_set_error(s->session, SSH_FATAL,
"ssh_socket_connect called on socket not unconnected");
Expand All @@ -854,7 +864,7 @@ int ssh_socket_connect(ssh_socket s,
return SSH_ERROR;
}
ssh_socket_set_fd(s,fd);

return SSH_OK;
}

Expand Down