Update libssh

This commit is contained in:
Nicolas Viennot 2013-10-04 16:34:20 -04:00
parent 8a87170c8a
commit bb5634ce20
18 changed files with 626 additions and 51 deletions

View File

@ -109,7 +109,9 @@ install(
# in tree build settings
configure_file(libssh-build-tree-settings.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/libssh-build-tree-settings.cmake @ONLY)
add_subdirectory(examples)
if (WITH_EXAMPLES)
add_subdirectory(examples)
endif (WITH_EXAMPLES)
if (WITH_TESTING)
find_package(CMocka REQUIRED)

View File

@ -12,6 +12,7 @@ option(WITH_INTERNAL_DOC "Compile doxygen internal documentation" OFF)
option(WITH_TESTING "Build with unit tests" OFF)
option(WITH_CLIENT_TESTING "Build with client tests; requires a running sshd" OFF)
option(WITH_BENCHMARKS "Build benchmarks tools" OFF)
option(WITH_EXAMPLES "Build examples" ON)
if (WITH_ZLIB)
set(WITH_LIBZ ON)

View File

@ -0,0 +1,119 @@
curve25519-sha256@libssh.org.txt Aris Adamantiadis <aris@badcode.be>
21/9/2013
1. Introduction
This document describes the key exchange methode curve25519-sha256@libssh.org
for SSH version 2 protocol. It is provided as an alternative to the existing
key exchange mechanisms based on either Diffie-Hellman or Elliptic Curve Diffie-
Hellman [RFC5656].
The reason is the following : During summer of 2013, revelations from ex-
consultant at NSA Edward Snowden gave proof that NSA willingly inserts backdoors
into softwares, hardware components and published standards. While it is still
believed that the mathematics behind ECC cryptography are still sound and solid,
some people (including Bruce Schneier [SCHNEIER]), showed their lack of confidence
in NIST-published curves such as nistp256, nistp384, nistp521, for which constant
parameters (including the generator point) are defined without explanation. It
is also believed that NSA had a word to say in their definition. These curves
are not the most secure or fastest possible for their key sizes [DJB], and
researchers think it is possible that NSA have ways of cracking NIST curves.
It is also interesting to note that SSH belongs to the list of protocols the NSA
claims to be able to eavesdrop. Having a secure replacement would make passive
attacks much harder if such a backdoor exists.
However an alternative exists in the form of Curve25519. This algorithm has been
proposed in 2006 by DJB [Curve25519]. Its main stengths are its speed, its
constant-time run time (and resistance against side-channel attacks), and its
lack of nebulous hard-coded constants.
The reference version being used in this document is the one described in
[Curve25519] as implemented in the library NaCl [NaCl].
This document does not attempts to provide alternatives to the ecdsa-sha1-*
authentication keys.
2. Key exchange
The key exchange procedure is very similar to the one described chapter 4 of
[RFC5656]. Public ephemeral keys are transmitted over SSH encapsulated into
standard SSH strings.
The following is an overview of the key exchange process:
Client Server
------ ------
Generate ephemeral key pair.
SSH_MSG_KEX_ECDH_INIT -------->
Verify that client public key
length is 32 bytes.
Generate ephemeral key pair.
Compute shared secret.
Generate and sign exchange hash.
<-------- SSH_MSG_KEX_ECDH_REPLY
Verify that server public key length is 32 bytes.
* Verify host keys belong to server.
Compute shared secret.
Generate exchange hash.
Verify server's signature.
* Optional but strongly recommanded as this protects against MITM attacks.
This is implemented using the same messages as described in RFC5656 chapter 4
3. Method Name
The name of this key exchange method is "curve25519-sha256@libssh.org".
4. Implementation considerations
The whole method is based on the curve25519 scalar multiplication. In this
method, a private key is a scalar of 256 bits, and a public key is a point
of 256 bits.
4.1. Private key generation
A 32 bytes private key should be generated for each new connection,
using a secure PRNG. The following actions must be done on the private key:
mysecret[0] &= 248;
mysecret[31] &= 127;
mysecret[31] |= 64;
In order to keep the key valid. However, many cryptographic libraries will do
this automatically.
It should be noted that, in opposition to NIST curves, no special validation
should be done to ensure the result is a valid and secure private key.
4.2 Public key generation
The 32 bytes public key of either a client or a server must be generated using
the 32 bytes private key and a common generator base. This base is defined as 9
followed by all zeroes:
const unsigned char basepoint[32] = {9};
The public key is calculated using the cryptographic scalar multiplication:
const unsigned char privkey[32];
unsigned char pubkey[32];
crypto_scalarmult (pubkey, privkey, basepoint);
However some cryptographic libraries may provide a combined function:
crypto_scalarmult_base (pubkey, privkey);
It should be noted that, in opposition to NIST curves, no special validation
should be done to ensure the received public keys are valid curves point. The
Curve25519 algorithm ensure that every possible public key maps to a valid
ECC Point.
4.3 Shared secret generation
The shared secret, k, is defined in SSH specifications to be a big integer.
This number is calculated using the following procedure:
X is the 32 bytes point obtained by the scalar multiplication of the other
side's public key and the local private key scalar.
The whole 32 bytes of the number X are then converted into a big integer k.
This conversion follows the network byte order. This step differs from
RFC5656.
[RFC5656] http://tools.ietf.org/html/rfc5656
[SCHNEIER] https://www.schneier.com/blog/archives/2013/09/the_nsa_is_brea.html#c1675929
[DJB] http://cr.yp.to/talks/2013.05.31/slides-dan+tanja-20130531-4x3.pdf
[Curve25519] "Curve25519: new Diffie-Hellman speed records."
http://cr.yp.to/ecdh/curve25519-20060209.pdf

View File

@ -788,12 +788,17 @@ struct ssh_threads_callbacks_struct {
};
/**
* @brief sets the thread callbacks necessary if your program is using
* libssh in a multithreaded fashion. This function must be called first,
* outside of any threading context (in your main() for instance), before
* ssh_init().
* @param cb pointer to a ssh_threads_callbacks_struct structure, which contains
* the different callbacks to be set.
* @brief Set the thread callbacks structure.
*
* This is necessary if your program is using libssh in a multithreaded fashion.
* This function must be called first, outside of any threading context (in your
* main() function for instance), before you call ssh_init().
*
* @param[in] cb A pointer to a ssh_threads_callbacks_struct structure, which
* contains the different callbacks to be set.
*
* @returns Always returns SSH_OK.
*
* @see ssh_threads_callbacks_struct
* @see SSH_THREADS_PTHREAD
*/
@ -809,9 +814,13 @@ LIBSSH_API int ssh_threads_set_callbacks(struct ssh_threads_callbacks_struct
LIBSSH_API struct ssh_threads_callbacks_struct *ssh_threads_get_pthread(void);
/**
* @brief returns a pointer on the noop threads callbacks, to be used with
* ssh_threads_set_callbacks. These callbacks do nothing and are being used by
* default.
* @brief Get the noop threads callbacks structure
*
* This can be used with ssh_threads_set_callbacks. These callbacks do nothing
* and are being used by default.
*
* @return Always returns a valid pointer to the noop callbacks structure.
*
* @see ssh_threads_set_callbacks
*/
LIBSSH_API struct ssh_threads_callbacks_struct *ssh_threads_get_noop(void);

View File

@ -44,6 +44,7 @@
#endif
#include "libssh/ecdh.h"
#include "libssh/kex.h"
#include "libssh/curve25519.h"
enum ssh_key_exchange_e {
/* diffie-hellman-group1-sha1 */
@ -51,7 +52,9 @@ enum ssh_key_exchange_e {
/* diffie-hellman-group14-sha1 */
SSH_KEX_DH_GROUP14_SHA1,
/* ecdh-sha2-nistp256 */
SSH_KEX_ECDH_SHA2_NISTP256
SSH_KEX_ECDH_SHA2_NISTP256,
/* curve25519-sha256@libssh.org */
SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG
};
struct ssh_crypto_struct {
@ -60,6 +63,11 @@ struct ssh_crypto_struct {
EC_KEY *ecdh_privkey;
ssh_string ecdh_client_pubkey;
ssh_string ecdh_server_pubkey;
#endif
#ifdef HAVE_CURVE25519
ssh_curve25519_privkey curve25519_privkey;
ssh_curve25519_pubkey curve25519_client_pubkey;
ssh_curve25519_pubkey curve25519_server_pubkey;
#endif
ssh_string dh_server_signature; /* information used by dh_handshake. */
size_t digest_len; /* len of all the fields below */

View File

@ -0,0 +1,46 @@
/*
* This file is part of the SSH Library
*
* Copyright (c) 2013 by Aris Adamantiadis <aris@badcode.be>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation,
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef CURVE25519_H_
#define CURVE25519_H_
#include "config.h"
#include "libssh.h"
#ifdef WITH_NACL
#define HAVE_CURVE25519
#include <nacl/crypto_scalarmult_curve25519.h>
#define CURVE25519_PUBKEY_SIZE crypto_scalarmult_curve25519_BYTES
#define CURVE25519_PRIVKEY_SIZE crypto_scalarmult_curve25519_SCALARBYTES
typedef unsigned char ssh_curve25519_pubkey[CURVE25519_PUBKEY_SIZE];
typedef unsigned char ssh_curve25519_privkey[CURVE25519_PRIVKEY_SIZE];
#endif /* WITH_NACL */
int ssh_client_curve25519_init(ssh_session session);
int ssh_client_curve25519_reply(ssh_session session, ssh_buffer packet);
#ifdef WITH_SERVER
int ssh_server_curve25519_init(ssh_session session, ssh_buffer packet);
#endif /* WITH_SERVER */
#endif /* CURVE25519_H_ */

View File

@ -97,9 +97,6 @@ struct ssh_session_struct {
int openssh;
uint32_t send_seq;
uint32_t recv_seq;
/* status flags */
int closed;
int closed_by_except;
int connected;
/* !=0 when the user got a session handle */

View File

@ -76,6 +76,18 @@ if (WITH_GSSAPI AND GSSAPI_FOUND)
)
endif (WITH_GSSAPI AND GSSAPI_FOUND)
if (WITH_NACL AND NACL_FOUND)
set(LIBSSH_PRIVATE_INCLUDE_DIRS
${LIBSSH_PRIVATE_INCLUDE_DIRS}
${NACL_INCLUDE_DIR}
)
set(LIBSSH_LINK_LIBRARIES
${LIBSSH_LINK_LIBRARIES}
${NACL_LIBRARY}
)
endif (WITH_NACL AND NACL_FOUND)
set(LIBSSH_LINK_LIBRARIES
${LIBSSH_LINK_LIBRARIES}
CACHE INTERNAL "libssh link libraries"
@ -192,6 +204,13 @@ if (WITH_GSSAPI AND GSSAPI_FOUND)
)
endif (WITH_GSSAPI AND GSSAPI_FOUND)
if (WITH_NACL)
set(libssh_SRCS
${libssh_SRCS}
curve25519.c
)
endif (WITH_NACL)
include_directories(
${LIBSSH_PUBLIC_INCLUDE_DIRS}
${LIBSSH_PRIVATE_INCLUDE_DIRS}

View File

@ -312,7 +312,11 @@ static int channel_open(ssh_channel channel, const char *type_c, int window,
type_c, channel->local_channel);
pending:
/* wait until channel is opened by server */
err = ssh_handle_packets_termination(session, SSH_TIMEOUT_USER, ssh_channel_open_termination, channel);
err = ssh_handle_packets_termination(session,
SSH_TIMEOUT_DEFAULT,
ssh_channel_open_termination,
channel);
if (session->session_state == SSH_SESSION_STATE_ERROR)
err = SSH_ERROR;
end:
@ -1607,7 +1611,11 @@ static int channel_request(ssh_channel channel, const char *request,
return SSH_OK;
}
pending:
rc = ssh_handle_packets_termination(session,SSH_TIMEOUT_USER, ssh_channel_request_termination, channel);
rc = ssh_handle_packets_termination(session,
SSH_TIMEOUT_DEFAULT,
ssh_channel_request_termination,
channel);
if(session->session_state == SSH_SESSION_STATE_ERROR || rc == SSH_ERROR) {
channel->request_state = SSH_CHANNEL_REQ_STATE_ERROR;
}
@ -1983,8 +1991,11 @@ static ssh_channel ssh_channel_accept(ssh_session session, int channeltype,
struct ssh_iterator *iterator;
int t;
for (t = timeout_ms; t >= 0; t -= 50)
{
/*
* We sleep for 50 ms in ssh_handle_packets() and later sleep for
* 50 ms. So we need to decrement by 100 ms.
*/
for (t = timeout_ms; t >= 0; t -= 100) {
ssh_handle_packets(session, 50);
if (session->ssh_message_list) {
@ -2145,8 +2156,11 @@ static int global_request(ssh_session session, const char *request,
return SSH_OK;
}
pending:
rc = ssh_handle_packets_termination(session, SSH_TIMEOUT_USER,
ssh_global_request_termination, session);
rc = ssh_handle_packets_termination(session,
SSH_TIMEOUT_DEFAULT,
ssh_global_request_termination,
session);
if(rc==SSH_ERROR || session->session_state == SSH_SESSION_STATE_ERROR){
session->global_req_state = SSH_CHANNEL_REQ_STATE_ERROR;
}
@ -2640,8 +2654,8 @@ static int ssh_channel_read_termination(void *s){
* @param[in] is_stderr A boolean value to mark reading from the stderr flow.
*
* @return The number of bytes read, 0 on end of file or SSH_ERROR
* on error. Can return 0 if nothing is available in nonblocking
* mode.
* on error. In nonblocking mode it Can return 0 if no data
* is available or SSH_AGAIN.
*
* @warning This function may return less than count bytes of data, and won't
* block until count bytes have been read.
@ -2924,8 +2938,10 @@ int ssh_channel_get_exit_status(ssh_channel channel) {
if(channel == NULL) {
return SSH_ERROR;
}
rc = ssh_handle_packets_termination(channel->session, SSH_TIMEOUT_USER,
ssh_channel_exit_status_termination, channel);
rc = ssh_handle_packets_termination(channel->session,
SSH_TIMEOUT_DEFAULT,
ssh_channel_exit_status_termination,
channel);
if (rc == SSH_ERROR || channel->session->session_state ==
SSH_SESSION_STATE_ERROR)
return SSH_ERROR;

View File

@ -196,6 +196,11 @@ static int dh_handshake(ssh_session session) {
case SSH_KEX_ECDH_SHA2_NISTP256:
rc = ssh_client_ecdh_init(session);
break;
#endif
#ifdef HAVE_CURVE25519
case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
rc = ssh_client_curve25519_init(session);
break;
#endif
default:
rc = SSH_ERROR;
@ -579,6 +584,14 @@ char *ssh_get_issue_banner(ssh_session session) {
* @param[in] session The SSH session to use.
*
* @return The version number if available, 0 otherwise.
*
* @code
* int openssh = ssh_get_openssh_version();
*
* if (openssh == SSH_INT_VERSION(6, 1, 0)) {
* printf("Version match!\m");
* }
* @endcode
*/
int ssh_get_openssh_version(ssh_session session) {
if (session == NULL) {

285
libssh/src/curve25519.c Normal file
View File

@ -0,0 +1,285 @@
/*
* curve25519.c - Curve25519 ECDH functions for key exchange
* curve25519-sha256@libssh.org
*
* This file is part of the SSH Library
*
* Copyright (c) 2013 by Aris Adamantiadis <aris@badcode.be>
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 2.1 of the License.
*
* The SSH Library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the SSH Library; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*/
#include "config.h"
#include "libssh/curve25519.h"
#ifdef HAVE_CURVE25519
#include "nacl/crypto_scalarmult_curve25519.h"
#include "libssh/ssh2.h"
#include "libssh/buffer.h"
#include "libssh/priv.h"
#include "libssh/session.h"
#include "libssh/crypto.h"
#include "libssh/dh.h"
#include "libssh/pki.h"
/** @internal
* @brief Starts curve25519-sha256@libssh.org key exchange
*/
int ssh_client_curve25519_init(ssh_session session){
ssh_string client_pubkey;
int rc;
rc = buffer_add_u8(session->out_buffer, SSH2_MSG_KEX_ECDH_INIT);
if (rc < 0) {
return SSH_ERROR;
}
rc = ssh_get_random(session->next_crypto->curve25519_privkey, CURVE25519_PRIVKEY_SIZE, 1);
if (rc == 0){
ssh_set_error(session, SSH_FATAL, "PRNG error");
return SSH_ERROR;
}
crypto_scalarmult_curve25519_base(session->next_crypto->curve25519_client_pubkey,
session->next_crypto->curve25519_privkey);
client_pubkey = ssh_string_new(CURVE25519_PUBKEY_SIZE);
if (client_pubkey == NULL) {
return SSH_ERROR;
}
ssh_string_fill(client_pubkey, session->next_crypto->curve25519_client_pubkey,
CURVE25519_PUBKEY_SIZE);
rc = buffer_add_ssh_string(session->out_buffer,client_pubkey);
if (rc < 0) {
ssh_string_free(client_pubkey);
return SSH_ERROR;
}
rc = packet_send(session);
return rc;
}
static int ssh_curve25519_build_k(ssh_session session) {
ssh_curve25519_pubkey k;
session->next_crypto->k = bignum_new();
if (session->next_crypto->k == NULL) {
return SSH_ERROR;
}
if (session->server)
crypto_scalarmult_curve25519(k, session->next_crypto->curve25519_privkey,
session->next_crypto->curve25519_client_pubkey);
else
crypto_scalarmult_curve25519(k, session->next_crypto->curve25519_privkey,
session->next_crypto->curve25519_server_pubkey);
BN_bin2bn(k, CURVE25519_PUBKEY_SIZE, session->next_crypto->k);
#ifdef DEBUG_CRYPTO
ssh_print_hexa("Session server cookie",
session->next_crypto->server_kex.cookie, 16);
ssh_print_hexa("Session client cookie",
session->next_crypto->client_kex.cookie, 16);
ssh_print_bignum("Shared secret key", session->next_crypto->k);
#endif
return 0;
}
/** @internal
* @brief parses a SSH_MSG_KEX_ECDH_REPLY packet and sends back
* a SSH_MSG_NEWKEYS
*/
int ssh_client_curve25519_reply(ssh_session session, ssh_buffer packet){
ssh_string q_s_string = NULL;
ssh_string pubkey = NULL;
ssh_string signature = NULL;
int rc;
pubkey = buffer_get_ssh_string(packet);
if (pubkey == NULL){
ssh_set_error(session,SSH_FATAL, "No public key in packet");
goto error;
}
/* this is the server host key */
session->next_crypto->server_pubkey = pubkey;
pubkey = NULL;
q_s_string = buffer_get_ssh_string(packet);
if (q_s_string == NULL) {
ssh_set_error(session,SSH_FATAL, "No Q_S ECC point in packet");
goto error;
}
if (ssh_string_len(q_s_string) != CURVE25519_PUBKEY_SIZE){
ssh_set_error(session, SSH_FATAL, "Incorrect size for server Curve25519 public key: %d",
ssh_string_len(q_s_string));
ssh_string_free(q_s_string);
goto error;
}
memcpy(session->next_crypto->curve25519_server_pubkey, ssh_string_data(q_s_string), CURVE25519_PUBKEY_SIZE);
signature = buffer_get_ssh_string(packet);
if (signature == NULL) {
ssh_set_error(session, SSH_FATAL, "No signature in packet");
goto error;
}
session->next_crypto->dh_server_signature = signature;
signature=NULL; /* ownership changed */
/* TODO: verify signature now instead of waiting for NEWKEYS */
if (ssh_curve25519_build_k(session) < 0) {
ssh_set_error(session, SSH_FATAL, "Cannot build k number");
goto error;
}
/* Send the MSG_NEWKEYS */
if (buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) {
goto error;
}
rc=packet_send(session);
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
return rc;
error:
return SSH_ERROR;
}
#ifdef WITH_SERVER
/** @brief Parse a SSH_MSG_KEXDH_INIT packet (server) and send a
* SSH_MSG_KEXDH_REPLY
*/
int ssh_server_curve25519_init(ssh_session session, ssh_buffer packet){
/* ECDH keys */
ssh_string q_c_string;
ssh_string q_s_string;
/* SSH host keys (rsa,dsa,ecdsa) */
ssh_key privkey;
ssh_string sig_blob = NULL;
int rc;
/* Extract the client pubkey from the init packet */
q_c_string = buffer_get_ssh_string(packet);
if (q_c_string == NULL) {
ssh_set_error(session,SSH_FATAL, "No Q_C ECC point in packet");
return SSH_ERROR;
}
if (ssh_string_len(q_c_string) != CURVE25519_PUBKEY_SIZE){
ssh_set_error(session, SSH_FATAL, "Incorrect size for server Curve25519 public key: %d",
ssh_string_len(q_c_string));
ssh_string_free(q_c_string);
return SSH_ERROR;
}
memcpy(session->next_crypto->curve25519_client_pubkey,
ssh_string_data(q_c_string), CURVE25519_PUBKEY_SIZE);
ssh_string_free(q_c_string);
/* Build server's keypair */
rc = ssh_get_random(session->next_crypto->curve25519_privkey, CURVE25519_PRIVKEY_SIZE, 1);
if (rc == 0){
ssh_set_error(session, SSH_FATAL, "PRNG error");
return SSH_ERROR;
}
crypto_scalarmult_curve25519_base(session->next_crypto->curve25519_server_pubkey,
session->next_crypto->curve25519_privkey);
q_s_string = ssh_string_new(CURVE25519_PUBKEY_SIZE);
if (q_s_string == NULL) {
return SSH_ERROR;
}
ssh_string_fill(q_s_string, session->next_crypto->curve25519_server_pubkey,
CURVE25519_PUBKEY_SIZE);
rc = buffer_add_u8(session->out_buffer, SSH2_MSG_KEX_ECDH_REPLY);
if (rc < 0) {
ssh_set_error_oom(session);
return SSH_ERROR;
}
/* build k and session_id */
rc = ssh_curve25519_build_k(session);
if (rc < 0) {
ssh_set_error(session, SSH_FATAL, "Cannot build k number");
return SSH_ERROR;
}
/* privkey is not allocated */
rc = ssh_get_key_params(session, &privkey);
if (rc == SSH_ERROR) {
return SSH_ERROR;
}
rc = make_sessionid(session);
if (rc != SSH_OK) {
ssh_set_error(session, SSH_FATAL, "Could not create a session id");
return SSH_ERROR;
}
/* add host's public key */
rc = buffer_add_ssh_string(session->out_buffer,
session->next_crypto->server_pubkey);
if (rc < 0) {
ssh_set_error_oom(session);
return SSH_ERROR;
}
/* add ecdh public key */
rc = buffer_add_ssh_string(session->out_buffer, q_s_string);
ssh_string_free(q_s_string);
if (rc < 0) {
ssh_set_error_oom(session);
return SSH_ERROR;
}
/* add signature blob */
sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey);
if (sig_blob == NULL) {
ssh_set_error(session, SSH_FATAL, "Could not sign the session id");
return SSH_ERROR;
}
rc = buffer_add_ssh_string(session->out_buffer, sig_blob);
ssh_string_free(sig_blob);
if (rc < 0) {
ssh_set_error_oom(session);
return SSH_ERROR;
}
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEX_ECDH_REPLY sent");
rc = packet_send(session);
if (rc == SSH_ERROR) {
return SSH_ERROR;
}
/* Send the MSG_NEWKEYS */
rc = buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS);
if (rc < 0) {
return SSH_ERROR;;
}
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
rc = packet_send(session);
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
return rc;
}
#endif /* WITH_SERVER */
#endif /* HAVE_CURVE25519 */

View File

@ -770,6 +770,18 @@ int make_sessionid(ssh_session session) {
if (rc < 0) {
goto error;
}
#endif
#ifdef HAVE_CURVE25519
} else if(session->next_crypto->kex_type == SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG){
rc = buffer_add_u32(buf, htonl(CURVE25519_PUBKEY_SIZE));
rc += buffer_add_data(buf, session->next_crypto->curve25519_client_pubkey,
CURVE25519_PUBKEY_SIZE);
rc += buffer_add_u32(buf, htonl(CURVE25519_PUBKEY_SIZE));
rc += buffer_add_data(buf, session->next_crypto->curve25519_server_pubkey,
CURVE25519_PUBKEY_SIZE);
if (rc != SSH_OK) {
goto error;
}
#endif
}
num = make_bignum_string(session->next_crypto->k);
@ -800,6 +812,7 @@ int make_sessionid(ssh_session session) {
session->next_crypto->secret_hash);
break;
case SSH_KEX_ECDH_SHA2_NISTP256:
case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
session->next_crypto->digest_len = SHA256_DIGEST_LENGTH;
session->next_crypto->mac_type = SSH_MAC_SHA256;
session->next_crypto->secret_hash = malloc(session->next_crypto->digest_len);

View File

@ -34,6 +34,7 @@
#include "libssh/session.h"
#include "libssh/ssh2.h"
#include "libssh/string.h"
#include "libssh/curve25519.h"
#ifdef HAVE_LIBGCRYPT
# define BLOWFISH "blowfish-cbc,"
@ -63,14 +64,21 @@
#define ZLIB "none"
#endif
#ifdef HAVE_ECDH
#define KEY_EXCHANGE "ecdh-sha2-nistp256,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1"
#define HOSTKEYS "ecdsa-sha2-nistp256,ssh-rsa,ssh-dss"
#ifdef HAVE_CURVE25519
#define CURVE25519 "curve25519-sha256@libssh.org,"
#else
#define KEY_EXCHANGE "diffie-hellman-group14-sha1,diffie-hellman-group1-sha1"
#define HOSTKEYS "ssh-rsa,ssh-dss"
#define CURVE25519 ""
#endif
#ifdef HAVE_ECDH
#define ECDH "ecdh-sha2-nistp256,"
#define HOSTKEYS "ecdsa-sha2-nistp256,ssh-rsa,ssh-dss"
#else
#define HOSTKEYS "ssh-rsa,ssh-dss"
#define ECDH ""
#endif
#define KEY_EXCHANGE CURVE25519 ECDH "diffie-hellman-group14-sha1,diffie-hellman-group1-sha1"
#define KEX_METHODS_SIZE 10
/* NOTE: This is a fixed API and the index is defined by ssh_kex_types_e */
@ -412,6 +420,8 @@ int ssh_kex_select_methods (ssh_session session){
session->next_crypto->kex_type=SSH_KEX_DH_GROUP14_SHA1;
} else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "ecdh-sha2-nistp256") == 0){
session->next_crypto->kex_type=SSH_KEX_ECDH_SHA2_NISTP256;
} else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "curve25519-sha256@libssh.org") == 0){
session->next_crypto->kex_type=SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG;
}
return SSH_OK;

View File

@ -126,6 +126,17 @@ static int ssh_execute_server_request(ssh_session session, ssh_message msg)
ssh_message_reply_default(msg);
}
return SSH_OK;
} else if (msg->auth_request.method == SSH_AUTH_METHOD_NONE &&
ssh_callbacks_exists(session->server_callbacks, auth_none_function)) {
rc = session->server_callbacks->auth_none_function(session,
msg->auth_request.username, session->server_callbacks->userdata);
if (rc == SSH_AUTH_SUCCESS || rc == SSH_AUTH_PARTIAL){
ssh_message_auth_reply_success(msg, rc == SSH_AUTH_PARTIAL);
} else {
ssh_message_reply_default(msg);
}
return SSH_OK;
}
break;

View File

@ -35,6 +35,7 @@
#include "libssh/session.h"
#include "libssh/socket.h"
#include "libssh/ssh2.h"
#include "libssh/curve25519.h"
/**
* @internal
@ -102,6 +103,11 @@ SSH_PACKET_CALLBACK(ssh_packet_dh_reply){
case SSH_KEX_ECDH_SHA2_NISTP256:
rc = ssh_client_ecdh_reply(session, packet);
break;
#endif
#ifdef HAVE_CURVE25519
case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
rc = ssh_client_curve25519_reply(session, packet);
break;
#endif
default:
ssh_set_error(session,SSH_FATAL,"Wrong kex type in ssh_packet_dh_reply");

View File

@ -349,8 +349,8 @@ void ssh_signature_free(ssh_signature sig)
*
* @param[in] auth_data Private data passed to the auth function.
*
* @param[out] pkey A pointer where the key can be stored. You need
* to free the memory.
* @param[out] pkey A pointer where the allocated key can be stored. You
* need to free the memory.
*
* @return SSH_ERROR in case of error, SSH_OK otherwise.
*
@ -397,8 +397,8 @@ int ssh_pki_import_privkey_base64(const char *b64_key,
*
* @param[in] auth_data Private data passed to the auth function.
*
* @param[out] pkey A pointer to store the ssh_key. You need to free the
* key.
* @param[out] pkey A pointer to store the allocated ssh_key. You need to
* free the key.
*
* @returns SSH_OK on success, SSH_EOF if the file doesn't exist or permission
* denied, SSH_ERROR otherwise.
@ -684,8 +684,8 @@ fail:
*
* @param[in] type The type of the key to format.
*
* @param[out] pkey A pointer where the key can be stored. You need
* to free the memory.
* @param[out] pkey A pointer where the allocated key can be stored. You
* need to free the memory.
*
* @return SSH_OK on success, SSH_ERROR on error.
*
@ -728,8 +728,8 @@ int ssh_pki_import_pubkey_base64(const char *b64_key,
* @param[in] key_blob The key blob to import as specified in RFC 4253 section
* 6.6 "Public Key Algorithms".
*
* @param[out] pkey A pointer where the key can be stored. You need
* to free the memory.
* @param[out] pkey A pointer where the allocated key can be stored. You
* need to free the memory.
*
* @return SSH_OK on success, SSH_ERROR on error.
*
@ -789,8 +789,8 @@ fail:
*
* @param[in] filename The path to the public key.
*
* @param[out] pkey A pointer to store the public key. You need to free the
* memory.
* @param[out] pkey A pointer to store the allocated public key. You need to
* free the memory.
*
* @returns SSH_OK on success, SSH_EOF if the file doesn't exist or permission
* denied, SSH_ERROR otherwise.
@ -875,17 +875,20 @@ int ssh_pki_import_pubkey_file(const char *filename, ssh_key *pkey)
/**
* @brief Generates a keypair.
*
* @param[in] type Type of key to create
*
* @param[in] parameter Parameter to the creation of key:
* rsa : length of the key in bits (e.g. 1024, 2048, 4096)
* dsa : length of the key in bits (e.g. 1024, 2048, 3072)
* ecdsa : bits of the key (e.g. 256, 384, 512)
* @param[out] pkey A pointer to store the private key. You need to free the
* memory.
* @param[out] pkey A pointer to store the allocated private key. You need
* to free the memory.
*
* @return SSH_OK on success, SSH_ERROR on error.
*
* @warning Generating a key pair may take some time.
*/
int ssh_pki_generate(enum ssh_keytypes_e type, int parameter,
ssh_key *pkey){
int rc;
@ -1000,7 +1003,8 @@ int ssh_pki_export_pubkey_blob(const ssh_key key,
*
* @param[in] key The key to hash
*
* @param[out] b64_key A pointer to store the base64 hased key.
* @param[out] b64_key A pointer to store the allocated base64 hashed key. You
* need to free the buffer.
*
* @return SSH_OK on success, SSH_ERROR on error.
*

View File

@ -58,6 +58,7 @@
#include "libssh/dh.h"
#include "libssh/messages.h"
#include "libssh/options.h"
#include "libssh/curve25519.h"
#define set_status(session, status) do {\
if (session->common.callbacks && session->common.callbacks->connect_status_function) \
@ -182,6 +183,11 @@ SSH_PACKET_CALLBACK(ssh_packet_kexdh_init){
case SSH_KEX_ECDH_SHA2_NISTP256:
rc = ssh_server_ecdh_init(session, packet);
break;
#endif
#ifdef HAVE_CURVE25519
case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
rc = ssh_server_curve25519_init(session, packet);
break;
#endif
default:
ssh_set_error(session,SSH_FATAL,"Wrong kex type in ssh_packet_kexdh_init");

View File

@ -115,6 +115,17 @@ ssh_session ssh_new(void) {
goto err;
}
#ifdef HAVE_ECC
id = strdup("%d/id_ecdsa");
if (id == NULL) {
goto err;
}
rc = ssh_list_append(session->opts.identity, id);
if (rc == SSH_ERROR) {
goto err;
}
#endif
id = strdup("%d/id_rsa");
if (id == NULL) {
goto err;
@ -268,7 +279,10 @@ void ssh_free(ssh_session session) {
/**
* @brief get the server banner
*
* @param[in] session The SSH session
*
* @return Returns the server banner string or NULL.
*/
const char* ssh_get_serverbanner(ssh_session session) {
if(!session) {
@ -300,8 +314,6 @@ void ssh_silent_disconnect(ssh_session session) {
* @param[in] session The ssh session to change.
*
* @param[in] blocking Zero for nonblocking mode.
*
* \bug nonblocking code is in development and won't work as expected
*/
void ssh_set_blocking(ssh_session session, int blocking) {
if (session == NULL) {
@ -577,7 +589,7 @@ int ssh_get_status(ssh_session session) {
socketstate = ssh_socket_get_status(session->socket);
if (session->closed) {
if (session->session_state == SSH_SESSION_STATE_DISCONNECTED) {
r |= SSH_CLOSED;
}
if (socketstate & SSH_READ_PENDING) {
@ -586,7 +598,8 @@ int ssh_get_status(ssh_session session) {
if (socketstate & SSH_WRITE_PENDING) {
r |= SSH_WRITE_PENDING;
}
if ((session->closed && (socketstate & SSH_CLOSED_ERROR)) ||
if ((session->session_state == SSH_SESSION_STATE_DISCONNECTED &&
(socketstate & SSH_CLOSED_ERROR)) ||
session->session_state == SSH_SESSION_STATE_ERROR) {
r |= SSH_CLOSED_ERROR;
}
@ -610,12 +623,9 @@ const char *ssh_get_disconnect_message(ssh_session session) {
return NULL;
}
if (!session->closed) {
if (session->session_state != SSH_SESSION_STATE_DISCONNECTED) {
ssh_set_error(session, SSH_REQUEST_DENIED,
"Connection not closed yet");
} else if(session->closed_by_except) {
ssh_set_error(session, SSH_REQUEST_DENIED,
"Connection closed by socket error");
} else if(!session->discon_msg) {
ssh_set_error(session, SSH_FATAL,
"Connection correctly closed but no disconnect message");