1
0
mirror of https://github.com/libssh2/libssh2.git synced 2025-07-31 00:03:08 +03:00

Agent forwarding implementation (#752)

This PR contains a series of patches that date back many years and I
believe were discussed on the mailing list, but never merged. We have
been using these in our local copy of libssh2 without issue since 2015,
if not earlier. I believe this is the full set of changes, as we tried
to use comments to mark where our copy of libssh2 differs from the
canonical version.

This also contains changes I made earlier this year, but which were not
discussed on the mailing list, to support certificates and FIDO2 keys
with agent forwarding.

Note that this is not a complete implementation of agent forwarding, as
that is outside the scope of libssh2. Clients still need to provide
their own implementation that parses ssh-agent methods after calling
libssh2_channel_read() and calls the appropriate callback messages in
libssh2. See the man page changes in this PR for more details.

Integration-patches-by: Viktor Szakats

* prefer size_t
* prefer unsigned int over u_int in public function
* add const
* docs, indent, checksrc, debug call, compiler warning fixes
This commit is contained in:
Michael Buckley
2023-04-22 01:54:20 -07:00
committed by GitHub
parent fba0b52b6a
commit bc4e619e76
12 changed files with 551 additions and 26 deletions

View File

@ -10,6 +10,7 @@ dist_man_MANS = \
libssh2_agent_init.3 \ libssh2_agent_init.3 \
libssh2_agent_list_identities.3 \ libssh2_agent_list_identities.3 \
libssh2_agent_set_identity_path.3 \ libssh2_agent_set_identity_path.3 \
libssh2_agent_sign.3 \
libssh2_agent_userauth.3 \ libssh2_agent_userauth.3 \
libssh2_banner_set.3 \ libssh2_banner_set.3 \
libssh2_base64_decode.3 \ libssh2_base64_decode.3 \

52
docs/libssh2_agent_sign.3 Normal file
View File

@ -0,0 +1,52 @@
.TH libssh2_agent_sign 3 "1 Oct 2022" "libssh2 1.11.0" "libssh2 manual"
.SH NAME
libssh2_agent_sign - sign data, with the help of ssh-agent
.SH SYNOPSIS
.nf
#include <libssh2.h>
int
libssh2_agent_sign(LIBSSH2_AGENT *agent,
struct libssh2_agent_publickey *identity,
unsigned char **sig,
size_t *s_len,
const unsigned char *data,
size_t d_len,
const char *method,
unsigned int method_len);
.fi
.SH DESCRIPTION
\fIagent\fP - ssh-agent handle as returned by
.BR libssh2_agent_init(3)
\fIidentity\fP - Public key to authenticate with, as returned by
.BR libssh2_agent_get_identity(3)
\fIsig\fP - A pointer to a buffer in which to place the signature. The caller
is responsible for freeing the signature with LIBSSH2_FREE.
\fIs_len\fP - A pointer to the length of the sig parameter.
\fIdata\fP - The data to sign.
\fId_len\fP - The length of the data parameter.
\fImethod\fP - A buffer indicating the signing method. This should match the
string at the start of identity->blob.
\fImethod_len\fP - The length of the method parameter.
Sign data using an ssh-agent. This function can be used in a callback
registered with libssh2_session_callback_set(3) using
LIBSSH2_CALLBACK_AUTHAGENT_SIGN to sign an authentication challenge from a
server. However, the client is responsible for implementing the code that calls
this callback in response to a SSH2_AGENTC_SIGN_REQUEST message.
.SH RETURN VALUE
Returns 0 if succeeded, or a negative value for error.
.SH AVAILABILITY
Added in libssh2 1.11.0
.SH SEE ALSO
.BR libssh2_agent_init(3)
.BR libssh2_agent_get_identity(3)
.BR libssh2_agent_userauth(3)
.BR libssh2_session_callback_set(3)

View File

@ -30,3 +30,4 @@ Added in libssh2 1.2
.SH SEE ALSO .SH SEE ALSO
.BR libssh2_agent_init(3) .BR libssh2_agent_init(3)
.BR libssh2_agent_get_identity(3) .BR libssh2_agent_get_identity(3)
.BR libssh2_agent_sign(3)

View File

@ -71,8 +71,67 @@ to the abstract pointer set in the \fIlibssh2_session_init_ex(3)\fP call.
The callback returns the number of bytes read, or -1 for error. The special The callback returns the number of bytes read, or -1 for error. The special
return code \fB-EAGAIN\fP can be returned to signal that the read was aborted return code \fB-EAGAIN\fP can be returned to signal that the read was aborted
to prevent getting blocked and it needs to be called again. to prevent getting blocked and it needs to be called again.
.IP LIBSSH2_CALLBACK_AUTHAGENT
Called during authentication process to allow the client to connect to the
ssh-agent and perform any setup, such as configuring the agent or adding keys.
The prototype of the callback:
.nf
void authagent(LIBSSH2_SESSION* session, LIBSSH2_CHANNEL *channel,
void **abstract);
.fi
.IP LIBSSH2_CALLBACK_AUTHAGENT_IDENTITIES
Not called by libssh2. The client is responsible for calling this method when
a SSH2_AGENTC_REQUEST_IDENTITIES message has been received.
The prototype of the callback:
.nf
void identities(LIBSSH2_SESSION* session, void *buffer,
const char *agent_path,
void **abstract)
.fi
\fBbuffer\fP must be filled in by the callback. Different clients may implement
this differently. For example, one client may pass in an unsigned char ** for
this parameter, while another may pass in a pointer to a struct.
Regardless of the type of buffer used, the client will need to send back a list
of identities in the following format.
uint32 buffer length
uint32 number of entries
entries
Where each entry in the entries list is of the format:
string data
cstring comment
\fBagent_path\fP The path to a running ssh-agent on the client machine, from
which identities can be listed.
.IP LIBSSH2_CALLBACK_AUTHAGENT_SIGN
Not called by libssh2. The client is responsible for calling this method when
a SSH2_AGENTC_SIGN_REQUEST message has been received.
The prototype of the callback:
.nf
void sign(LIBSSH2_SESSION* session,
unsigned char *blob, unsigned int blen,
const unsigned char *data, unsigned int dlen,
unsigned char **sig, unsigned int *sig_len,
const char *agent_path,
void **abstract);
.fi
When interfacing with an ssh-agent installed on the client system, this method
can call libssh2_agent_sign(3) to perform signing.
.SH RETURN VALUE .SH RETURN VALUE
Pointer to previous callback handler. Returns NULL if no prior callback Pointer to previous callback handler. Returns NULL if no prior callback
handler was set or the callback type was unknown. handler was set or the callback type was unknown.
.SH SEE ALSO .SH SEE ALSO
.BR libssh2_session_init_ex(3) .BR libssh2_session_init_ex(3)
.BR libssh2_agent_sign(3)

View File

@ -9,6 +9,8 @@ int
libssh2_userauth_publickey_sk(LIBSSH2_SESSION *session, libssh2_userauth_publickey_sk(LIBSSH2_SESSION *session,
const char *username, const char *username,
size_t username_len, size_t username_len,
const unsigned char *publickeydata,
size_t publickeydata_len,
const char *privatekeydata, const char *privatekeydata,
size_t privatekeydata_len, size_t privatekeydata_len,
const char *passphrase, const char *passphrase,
@ -43,6 +45,13 @@ int name(LIBSSH2_SESSION *session, LIBSSH2_SK_SIG_INFO *sig_info,
\fIusername_len\fP - Length of username parameter. \fIusername_len\fP - Length of username parameter.
\fIpublickeydata\fP - Buffer containing the contents of a public key file. If
NULL, the public key will be extracted from the privatekeydata. When using
certificate authentication, this buffer should contain the public certificate
data.
\fIpublickeydata_len\fP - Length of public key data.
\fIprivatekeydata\fP - Buffer containing the contents of a private key file. \fIprivatekeydata\fP - Buffer containing the contents of a private key file.
\fIprivatekeydata_len\fP - Length of private key data. \fIprivatekeydata_len\fP - Length of private key data.

View File

@ -333,6 +333,22 @@ typedef struct _LIBSSH2_SK_SIG_INFO {
void name(LIBSSH2_SESSION *session, LIBSSH2_CHANNEL *channel, \ void name(LIBSSH2_SESSION *session, LIBSSH2_CHANNEL *channel, \
const char *shost, int sport, void **abstract) const char *shost, int sport, void **abstract)
#define LIBSSH2_AUTHAGENT_FUNC(name) \
void name(LIBSSH2_SESSION *session, LIBSSH2_CHANNEL *channel, \
void **abstract)
#define LIBSSH2_ADD_IDENTITIES_FUNC(name) \
void name(LIBSSH2_SESSION *session, void *buffer, \
const char *agent_path, void **abstract)
#define LIBSSH2_AUTHAGENT_SIGN_FUNC(name) \
int name(LIBSSH2_SESSION* session, \
unsigned char *blob, unsigned int blen, \
const unsigned char *data, unsigned int dlen, \
unsigned char **signature, unsigned int *sigLen, \
const char *agentPath, \
void **abstract)
#define LIBSSH2_CHANNEL_CLOSE_FUNC(name) \ #define LIBSSH2_CHANNEL_CLOSE_FUNC(name) \
void name(LIBSSH2_SESSION *session, void **session_abstract, \ void name(LIBSSH2_SESSION *session, void **session_abstract, \
LIBSSH2_CHANNEL *channel, void **channel_abstract) LIBSSH2_CHANNEL *channel, void **channel_abstract)
@ -348,13 +364,16 @@ typedef struct _LIBSSH2_SK_SIG_INFO {
int flags, void **abstract) int flags, void **abstract)
/* libssh2_session_callback_set() constants */ /* libssh2_session_callback_set() constants */
#define LIBSSH2_CALLBACK_IGNORE 0 #define LIBSSH2_CALLBACK_IGNORE 0
#define LIBSSH2_CALLBACK_DEBUG 1 #define LIBSSH2_CALLBACK_DEBUG 1
#define LIBSSH2_CALLBACK_DISCONNECT 2 #define LIBSSH2_CALLBACK_DISCONNECT 2
#define LIBSSH2_CALLBACK_MACERROR 3 #define LIBSSH2_CALLBACK_MACERROR 3
#define LIBSSH2_CALLBACK_X11 4 #define LIBSSH2_CALLBACK_X11 4
#define LIBSSH2_CALLBACK_SEND 5 #define LIBSSH2_CALLBACK_SEND 5
#define LIBSSH2_CALLBACK_RECV 6 #define LIBSSH2_CALLBACK_RECV 6
#define LIBSSH2_CALLBACK_AUTHAGENT 7
#define LIBSSH2_CALLBACK_AUTHAGENT_IDENTITIES 8
#define LIBSSH2_CALLBACK_AUTHAGENT_SIGN 9
/* libssh2_session_method_pref() constants */ /* libssh2_session_method_pref() constants */
#define LIBSSH2_METHOD_KEX 0 #define LIBSSH2_METHOD_KEX 0
@ -747,6 +766,8 @@ LIBSSH2_API int
libssh2_userauth_publickey_sk(LIBSSH2_SESSION *session, libssh2_userauth_publickey_sk(LIBSSH2_SESSION *session,
const char *username, const char *username,
size_t username_len, size_t username_len,
const unsigned char *pubkeydata,
size_t pubkeydata_len,
const char *privatekeydata, const char *privatekeydata,
size_t privatekeydata_len, size_t privatekeydata_len,
const char *passphrase, const char *passphrase,
@ -1331,6 +1352,23 @@ libssh2_agent_userauth(LIBSSH2_AGENT *agent,
const char *username, const char *username,
struct libssh2_agent_publickey *identity); struct libssh2_agent_publickey *identity);
/*
* libssh2_agent_sign()
*
* Sign a payload using a system-installed ssh-agent.
*
* Returns 0 if succeeded, or a negative value for error.
*/
LIBSSH2_API int
libssh2_agent_sign(LIBSSH2_AGENT *agent,
struct libssh2_agent_publickey *identity,
unsigned char **sig,
size_t *s_len,
const unsigned char *data,
size_t d_len,
const char *method,
unsigned int method_len);
/* /*
* libssh2_agent_disconnect() * libssh2_agent_disconnect()
* *

View File

@ -383,6 +383,7 @@ agent_sign(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len,
int rc; int rc;
unsigned char *method_name = NULL; unsigned char *method_name = NULL;
uint32_t sign_flags = 0; uint32_t sign_flags = 0;
ssize_t plain_len;
/* Create a request to sign the data */ /* Create a request to sign the data */
if(transctx->state == agent_NB_state_init) { if(transctx->state == agent_NB_state_init) {
@ -478,9 +479,13 @@ agent_sign(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len,
memcpy(method_name, s, method_len); memcpy(method_name, s, method_len);
s += method_len; s += method_len;
plain_len = plain_method((char *)session->userauth_pblc_method,
session->userauth_pblc_method_len);
/* check to see if we match requested */ /* check to see if we match requested */
if((size_t)method_len != session->userauth_pblc_method_len || if(((size_t)method_len != session->userauth_pblc_method_len &&
memcmp(method_name, session->userauth_pblc_method, method_len)) { method_len != plain_len) ||
memcmp(method_name, session->userauth_pblc_method, method_len)) {
_libssh2_debug((session, _libssh2_debug((session,
LIBSSH2_TRACE_KEX, LIBSSH2_TRACE_KEX,
"Agent sign method %.*s", "Agent sign method %.*s",
@ -829,6 +834,57 @@ libssh2_agent_userauth(LIBSSH2_AGENT *agent,
return rc; return rc;
} }
/*
* libssh2_agent_sign
*
* Sign a payload using a system-installed ssh-agent.
*
* Returns 0 if succeeded, or a negative value for error.
*/
LIBSSH2_API int
libssh2_agent_sign(LIBSSH2_AGENT *agent,
struct libssh2_agent_publickey *identity,
unsigned char **sig,
size_t *s_len,
const unsigned char *data,
size_t d_len,
const char *method,
unsigned int method_len)
{
void *abstract = agent;
int rc;
uint32_t methodLen;
if(agent->session->userauth_pblc_state == libssh2_NB_state_idle) {
memset(&agent->transctx, 0, sizeof(agent->transctx));
agent->identity = identity->node;
}
if(identity->blob_len < sizeof(uint32_t)) {
return LIBSSH2_ERROR_BUFFER_TOO_SMALL;
}
methodLen = _libssh2_ntohu32(identity->blob);
if(identity->blob_len < sizeof(uint32_t) + methodLen) {
return LIBSSH2_ERROR_BUFFER_TOO_SMALL;
}
agent->session->userauth_pblc_method_len = method_len;
agent->session->userauth_pblc_method = LIBSSH2_ALLOC(agent->session,
method_len);
memcpy(agent->session->userauth_pblc_method, method, methodLen);
rc = agent_sign(agent->session, sig, s_len, data, d_len, &abstract);
LIBSSH2_FREE(agent->session, agent->session->userauth_pblc_method);
agent->session->userauth_pblc_method = NULL;
agent->session->userauth_pblc_method_len = 0;
return rc;
}
/* /*
* libssh2_agent_disconnect * libssh2_agent_disconnect
* *

View File

@ -1257,6 +1257,18 @@ static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_ed25519 = {
hostkey_method_ssh_ed25519_dtor, hostkey_method_ssh_ed25519_dtor,
}; };
static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_ed25519_cert = {
"ssh-ed25519-cert-v01@openssh.com",
SHA256_DIGEST_LENGTH,
hostkey_method_ssh_ed25519_init,
hostkey_method_ssh_ed25519_initPEM,
hostkey_method_ssh_ed25519_initPEMFromMemory,
hostkey_method_ssh_ed25519_sig_verify,
hostkey_method_ssh_ed25519_signv,
NULL, /* encrypt */
hostkey_method_ssh_ed25519_dtor,
};
#endif /* LIBSSH2_ED25519 */ #endif /* LIBSSH2_ED25519 */
@ -1271,6 +1283,7 @@ static const LIBSSH2_HOSTKEY_METHOD *hostkey_methods[] = {
#endif #endif
#if LIBSSH2_ED25519 #if LIBSSH2_ED25519
&hostkey_method_ssh_ed25519, &hostkey_method_ssh_ed25519,
&hostkey_method_ssh_ed25519_cert,
#endif #endif
#if LIBSSH2_RSA #if LIBSSH2_RSA
#if LIBSSH2_RSA_SHA2 #if LIBSSH2_RSA_SHA2

View File

@ -199,6 +199,21 @@ struct iovec {
channel->session->x11(((channel)->session), (channel), \ channel->session->x11(((channel)->session), (channel), \
(shost), (sport), (&(channel)->session->abstract)) (shost), (sport), (&(channel)->session->abstract))
#define LIBSSH2_AUTHAGENT(channel) \
channel->session->authagent(((channel)->session), (channel), \
(&(channel)->session->abstract))
#define LIBSSH2_ADD_IDENTITIES(session, buffer, agentPath) \
session->addLocalIdentities((session), (buffer), \
(agentPath), (&(session->abstract)))
#define LIBSSH2_AUTHAGENT_SIGN(session, blob, blen, \
data, dlen, sig, sigLen, \
agentPath) \
session->agentSignCallback((session), (blob), (blen), \
(data), (dlen), (sig), (sigLen), \
(agentPath), (&(session->abstract)))
#define LIBSSH2_CHANNEL_CLOSE(session, channel) \ #define LIBSSH2_CHANNEL_CLOSE(session, channel) \
channel->close_cb((session), &(session)->abstract, \ channel->close_cb((session), &(session)->abstract, \
(channel), &(channel)->abstract) (channel), &(channel)->abstract)
@ -238,7 +253,8 @@ typedef enum
libssh2_NB_state_jump3, libssh2_NB_state_jump3,
libssh2_NB_state_jump4, libssh2_NB_state_jump4,
libssh2_NB_state_jump5, libssh2_NB_state_jump5,
libssh2_NB_state_end libssh2_NB_state_end,
libssh2_NB_state_jumpauthagent
} libssh2_nonblocking_states; } libssh2_nonblocking_states;
typedef struct packet_require_state_t typedef struct packet_require_state_t
@ -344,6 +360,24 @@ typedef struct packet_x11_open_state_t
LIBSSH2_CHANNEL *channel; LIBSSH2_CHANNEL *channel;
} packet_x11_open_state_t; } packet_x11_open_state_t;
#define AuthAgentUnavail "Auth Agent unavailable"
typedef struct packet_authagent_state_t
{
libssh2_nonblocking_states state;
unsigned char packet[17 + (sizeof(AuthAgentUnavail) - 1)];
uint32_t sender_channel;
uint32_t initial_window_size;
uint32_t packet_size;
LIBSSH2_CHANNEL *channel;
} packet_authagent_state_t;
typedef enum
{
libssh2_requires_size_decryption = (1 << 0),
libssh2_requires_size_field_in_packet = (1 << 1)
} libssh2_crypt_flags;
struct _LIBSSH2_PACKET struct _LIBSSH2_PACKET
{ {
struct list_node node; /* linked list header */ struct list_node node; /* linked list header */
@ -518,7 +552,7 @@ typedef struct _libssh2_endpoint_data
char *lang_prefs; char *lang_prefs;
} libssh2_endpoint_data; } libssh2_endpoint_data;
#define PACKETBUFSIZE (1024*16) #define PACKETBUFSIZE MAX_SSH_PACKET_LEN
struct transportpacket struct transportpacket
{ {
@ -606,6 +640,9 @@ struct _LIBSSH2_SESSION
LIBSSH2_DISCONNECT_FUNC((*ssh_msg_disconnect)); LIBSSH2_DISCONNECT_FUNC((*ssh_msg_disconnect));
LIBSSH2_MACERROR_FUNC((*macerror)); LIBSSH2_MACERROR_FUNC((*macerror));
LIBSSH2_X11_OPEN_FUNC((*x11)); LIBSSH2_X11_OPEN_FUNC((*x11));
LIBSSH2_AUTHAGENT_FUNC((*authagent));
LIBSSH2_ADD_IDENTITIES_FUNC((*addLocalIdentities));
LIBSSH2_AUTHAGENT_SIGN_FUNC((*agentSignCallback));
LIBSSH2_SEND_FUNC((*send)); LIBSSH2_SEND_FUNC((*send));
LIBSSH2_RECV_FUNC((*recv)); LIBSSH2_RECV_FUNC((*recv));
@ -820,6 +857,7 @@ struct _LIBSSH2_SESSION
states */ states */
packet_queue_listener_state_t packAdd_Qlstn_state; packet_queue_listener_state_t packAdd_Qlstn_state;
packet_x11_open_state_t packAdd_x11open_state; packet_x11_open_state_t packAdd_x11open_state;
packet_authagent_state_t packAdd_authagent_state;
/* State variables used in fullpacket() */ /* State variables used in fullpacket() */
libssh2_nonblocking_states fullpacket_state; libssh2_nonblocking_states fullpacket_state;
@ -1151,6 +1189,8 @@ int _libssh2_pem_decode_integer(unsigned char **data, size_t *datalen,
/* global.c */ /* global.c */
void _libssh2_init_if_needed(void); void _libssh2_init_if_needed(void);
/* Utility function for certificate auth */
size_t plain_method(char *method, size_t method_len);
#define ARRAY_SIZE(a) (sizeof ((a)) / sizeof ((a)[0])) #define ARRAY_SIZE(a) (sizeof ((a)) / sizeof ((a)[0]))

View File

@ -460,6 +460,154 @@ packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data,
return 0; return 0;
} }
/*
* packet_authagent_open
*
* Open a connection to authentication agent
*/
static inline int
packet_authagent_open(LIBSSH2_SESSION * session,
unsigned char *data, size_t datalen,
packet_authagent_state_t *authagent_state)
{
int failure_code = SSH_OPEN_CONNECT_FAILED;
/* 17 = packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */
size_t packet_len = 17 + (sizeof(X11FwdUnAvil) - 1);
unsigned char *p;
LIBSSH2_CHANNEL *channel = authagent_state->channel;
int rc;
(void)datalen;
if(authagent_state->state == libssh2_NB_state_idle) {
unsigned char *s = data + (sizeof("auth-agent@openssh.org") - 1) + 5;
authagent_state->sender_channel = _libssh2_ntohu32(s);
s += 4;
authagent_state->initial_window_size = _libssh2_ntohu32(s);
s += 4;
authagent_state->packet_size = _libssh2_ntohu32(s);
_libssh2_debug((session, LIBSSH2_TRACE_CONN,
"Auth Agent Connection Received on channel %lu",
authagent_state->sender_channel));
authagent_state->state = libssh2_NB_state_allocated;
}
if(session->authagent) {
if(authagent_state->state == libssh2_NB_state_allocated) {
channel = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL));
authagent_state->channel = channel;
if(!channel) {
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"allocate a channel for new connection");
failure_code = SSH_OPEN_RESOURCE_SHORTAGE;
goto authagent_exit;
}
memset(channel, 0, sizeof(LIBSSH2_CHANNEL));
channel->session = session;
channel->channel_type_len = sizeof("auth agent") - 1;
channel->channel_type = LIBSSH2_ALLOC(session,
channel->channel_type_len +
1);
if(!channel->channel_type) {
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"allocate a channel for new connection");
LIBSSH2_FREE(session, channel);
failure_code = SSH_OPEN_RESOURCE_SHORTAGE;
goto authagent_exit;
}
memcpy(channel->channel_type, "auth agent",
channel->channel_type_len + 1);
channel->remote.id = authagent_state->sender_channel;
channel->remote.window_size_initial =
LIBSSH2_CHANNEL_WINDOW_DEFAULT;
channel->remote.window_size = LIBSSH2_CHANNEL_WINDOW_DEFAULT;
channel->remote.packet_size = LIBSSH2_CHANNEL_PACKET_DEFAULT;
channel->local.id = _libssh2_channel_nextid(session);
channel->local.window_size_initial =
authagent_state->initial_window_size;
channel->local.window_size = authagent_state->initial_window_size;
channel->local.packet_size = authagent_state->packet_size;
_libssh2_debug((session, LIBSSH2_TRACE_CONN,
"Auth Agent Connection established: channel "
"%lu/%lu win %lu/%lu packet %lu/%lu",
channel->local.id, channel->remote.id,
channel->local.window_size,
channel->remote.window_size,
channel->local.packet_size,
channel->remote.packet_size));
p = authagent_state->packet;
*(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION;
_libssh2_store_u32(&p, channel->remote.id);
_libssh2_store_u32(&p, channel->local.id);
_libssh2_store_u32(&p, channel->remote.window_size_initial);
_libssh2_store_u32(&p, channel->remote.packet_size);
authagent_state->state = libssh2_NB_state_created;
}
if(authagent_state->state == libssh2_NB_state_created) {
rc = _libssh2_transport_send(session, authagent_state->packet, 17,
NULL, 0);
if(rc == LIBSSH2_ERROR_EAGAIN) {
return rc;
}
else if(rc) {
authagent_state->state = libssh2_NB_state_idle;
return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"Unable to send channel open "
"confirmation");
}
/* Link the channel into the session */
_libssh2_list_add(&session->channels, &channel->node);
/* mess with stuff so we don't keep reading the same packet
over and over */
session->packet.total_num = 0;
session->fullpacket_state = libssh2_NB_state_idle;
/* Pass control to the callback, they may turn right around and
and free the channel, or actually use it */
LIBSSH2_AUTHAGENT(channel);
authagent_state->state = libssh2_NB_state_idle;
return 0;
}
}
else
failure_code = SSH_OPEN_RESOURCE_SHORTAGE;
/* fall-through */
authagent_exit:
p = authagent_state->packet;
*(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE;
_libssh2_store_u32(&p, authagent_state->sender_channel);
_libssh2_store_u32(&p, failure_code);
_libssh2_store_str(&p, AuthAgentUnavail, sizeof(AuthAgentUnavail) - 1);
_libssh2_htonu32(p, 0);
rc = _libssh2_transport_send(session, authagent_state->packet, packet_len,
NULL, 0);
if(rc == LIBSSH2_ERROR_EAGAIN) {
return rc;
}
else if(rc) {
authagent_state->state = libssh2_NB_state_idle;
return _libssh2_error(session, rc, "Unable to send open failure");
}
authagent_state->state = libssh2_NB_state_idle;
return 0;
}
/* /*
* _libssh2_packet_add * _libssh2_packet_add
* *
@ -513,6 +661,8 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
goto libssh2_packet_add_jump_point4; goto libssh2_packet_add_jump_point4;
case libssh2_NB_state_jump5: case libssh2_NB_state_jump5:
goto libssh2_packet_add_jump_point5; goto libssh2_packet_add_jump_point5;
case libssh2_NB_state_jumpauthagent:
goto libssh2_packet_add_jump_authagent;
default: /* nothing to do */ default: /* nothing to do */
break; break;
} }
@ -1051,6 +1201,20 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
rc = packet_x11_open(session, data, datalen, rc = packet_x11_open(session, data, datalen,
&session->packAdd_x11open_state); &session->packAdd_x11open_state);
} }
else if((datalen >= (sizeof("auth-agent@openssh.com") + 4)) &&
((sizeof("auth-agent@openssh.com") - 1) ==
_libssh2_ntohu32(data + 1)) &&
(memcmp(data + 5, "auth-agent@openssh.com",
sizeof("auth-agent@openssh.com") - 1) == 0)) {
/* init the state struct */
memset(&session->packAdd_authagent_state, 0,
sizeof(session->packAdd_authagent_state));
libssh2_packet_add_jump_authagent:
rc = packet_authagent_open(session, data, datalen,
&session->packAdd_authagent_state);
}
if(rc == LIBSSH2_ERROR_EAGAIN) if(rc == LIBSSH2_ERROR_EAGAIN)
return rc; return rc;

View File

@ -536,6 +536,21 @@ libssh2_session_callback_set(LIBSSH2_SESSION * session,
oldcb = session->recv; oldcb = session->recv;
session->recv = callback; session->recv = callback;
return oldcb; return oldcb;
case LIBSSH2_CALLBACK_AUTHAGENT:
oldcb = session->authagent;
session->authagent = callback;
return oldcb;
case LIBSSH2_CALLBACK_AUTHAGENT_IDENTITIES:
oldcb = session->addLocalIdentities;
session->addLocalIdentities = callback;
return oldcb;
case LIBSSH2_CALLBACK_AUTHAGENT_SIGN:
oldcb = session->agentSignCallback;
session->agentSignCallback = callback;
return oldcb;
} }
_libssh2_debug((session, LIBSSH2_TRACE_TRANS, "Setting Callback %d", _libssh2_debug((session, LIBSSH2_TRACE_TRANS, "Setting Callback %d",
cbtype)); cbtype));

View File

@ -1249,7 +1249,7 @@ libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session,
return rc; return rc;
} }
static size_t plain_method_len(const char *method, size_t method_len) size_t plain_method(char *method, size_t method_len)
{ {
if(!strncmp("ssh-rsa-cert-v01@openssh.com", if(!strncmp("ssh-rsa-cert-v01@openssh.com",
method, method,
@ -1268,6 +1268,29 @@ static size_t plain_method_len(const char *method, size_t method_len)
method_len)) { method_len)) {
return 19; return 19;
} }
if(!strncmp("ssh-ed25519-cert-v01@openssh.com",
method,
method_len)) {
return 11;
}
if(!strncmp("sk-ecdsa-sha2-nistp256-cert-v01@openssh.com",
method,
method_len)) {
const char *new_method = "sk-ecdsa-sha2-nistp256@openssh.com";
memcpy(method, new_method, strlen(new_method));
return strlen(new_method);
}
if(!strncmp("sk-ssh-ed25519-cert-v01@openssh.com",
method,
method_len)) {
const char *new_method = "sk-ssh-ed25519@openssh.com";
memcpy(method, new_method, strlen(new_method));
return strlen(new_method);
}
return method_len; return method_len;
} }
@ -1701,8 +1724,8 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session,
session->userauth_pblc_b = NULL; session->userauth_pblc_b = NULL;
session->userauth_pblc_method_len = session->userauth_pblc_method_len =
plain_method_len((const char *)session->userauth_pblc_method, plain_method((char *)session->userauth_pblc_method,
session->userauth_pblc_method_len); session->userauth_pblc_method_len);
if(strncmp((const char *)session->userauth_pblc_method, if(strncmp((const char *)session->userauth_pblc_method,
"sk-ecdsa-sha2-nistp256@openssh.com", "sk-ecdsa-sha2-nistp256@openssh.com",
@ -2291,6 +2314,8 @@ LIBSSH2_API int
libssh2_userauth_publickey_sk(LIBSSH2_SESSION *session, libssh2_userauth_publickey_sk(LIBSSH2_SESSION *session,
const char *username, const char *username,
size_t username_len, size_t username_len,
const unsigned char *publickeydata,
size_t publickeydata_len,
const char *privatekeydata, const char *privatekeydata,
size_t privatekeydata_len, size_t privatekeydata_len,
const char *passphrase, const char *passphrase,
@ -2298,11 +2323,19 @@ libssh2_userauth_publickey_sk(LIBSSH2_SESSION *session,
((*sign_callback)), ((*sign_callback)),
void **abstract) void **abstract)
{ {
int rc = LIBSSH2_ERROR_NONE;
unsigned char *tmp_method = NULL;
size_t tmp_method_len = 0;
unsigned char *tmp_publickeydata = NULL;
size_t tmp_publickeydata_len = 0;
unsigned char *pubkeydata = NULL; unsigned char *pubkeydata = NULL;
size_t pubkeydata_len = 0; size_t pubkeydata_len = 0;
LIBSSH2_PRIVKEY_SK sk_info = { 0 }; LIBSSH2_PRIVKEY_SK sk_info = { 0 };
void *sign_abstract = &sk_info; void *sign_abstract = &sk_info;
int rc;
sk_info.sign_callback = sign_callback; sk_info.sign_callback = sign_callback;
sk_info.orig_abstract = abstract; sk_info.orig_abstract = abstract;
@ -2310,37 +2343,81 @@ libssh2_userauth_publickey_sk(LIBSSH2_SESSION *session,
if(privatekeydata_len && privatekeydata) { if(privatekeydata_len && privatekeydata) {
if(_libssh2_sk_pub_keyfilememory(session, if(_libssh2_sk_pub_keyfilememory(session,
&session->userauth_pblc_method, &tmp_method,
&session->userauth_pblc_method_len, &tmp_method_len,
&pubkeydata, &pubkeydata_len, &tmp_publickeydata,
&tmp_publickeydata_len,
&(sk_info.algorithm), &(sk_info.algorithm),
&(sk_info.flags), &(sk_info.flags),
&(sk_info.application), &(sk_info.application),
&(sk_info.key_handle), &(sk_info.key_handle),
&(sk_info.handle_len), &(sk_info.handle_len),
privatekeydata, privatekeydata_len, privatekeydata, privatekeydata_len,
passphrase)) passphrase)) {
return _libssh2_error(session, LIBSSH2_ERROR_FILE, return _libssh2_error(session, LIBSSH2_ERROR_FILE,
"Unable to extract public key " "Unable to extract public key "
"from private key."); "from private key.");
}
else if(publickeydata_len == 0 || !publickeydata) {
session->userauth_pblc_method = tmp_method;
session->userauth_pblc_method_len = tmp_method_len;
pubkeydata_len = tmp_publickeydata_len;
pubkeydata = tmp_publickeydata;
}
else {
const char *ecdsa = "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com";
const char *ed25519 = "sk-ssh-ed25519-cert-v01@openssh.com";
if(tmp_method) {
LIBSSH2_FREE(session, tmp_method);
}
if(!strncmp((char *)publickeydata, ecdsa, strlen(ecdsa))) {
session->userauth_pblc_method_len = strlen(ecdsa);
session->userauth_pblc_method =
LIBSSH2_ALLOC(session, session->userauth_pblc_method_len);
memcpy(session->userauth_pblc_method, ecdsa,
session->userauth_pblc_method_len);
}
else if(!strncmp((char *)publickeydata, ed25519,
strlen(ed25519))) {
session->userauth_pblc_method_len = strlen(ed25519);
session->userauth_pblc_method =
LIBSSH2_ALLOC(session, session->userauth_pblc_method_len);
memcpy(session->userauth_pblc_method, ed25519,
session->userauth_pblc_method_len);
}
rc = memory_read_publickey(session,
&session->userauth_pblc_method,
&session->userauth_pblc_method_len,
&pubkeydata, &pubkeydata_len,
(char *)publickeydata,
publickeydata_len);
}
} }
else { else {
return _libssh2_error(session, LIBSSH2_ERROR_FILE, return _libssh2_error(session, LIBSSH2_ERROR_FILE,
"Invalid data in public and private key."); "Invalid data in public and private key.");
} }
rc = _libssh2_userauth_publickey(session, username, username_len, if(rc == LIBSSH2_ERROR_NONE) {
pubkeydata, pubkeydata_len,
libssh2_sign_sk, &sign_abstract);
while(rc == LIBSSH2_ERROR_EAGAIN) {
rc = _libssh2_userauth_publickey(session, username, username_len, rc = _libssh2_userauth_publickey(session, username, username_len,
pubkeydata, pubkeydata_len, pubkeydata, pubkeydata_len,
libssh2_sign_sk, &sign_abstract); libssh2_sign_sk, &sign_abstract);
while(rc == LIBSSH2_ERROR_EAGAIN) {
rc = _libssh2_userauth_publickey(session, username, username_len,
pubkeydata, pubkeydata_len,
libssh2_sign_sk, &sign_abstract);
}
} }
if(pubkeydata) if(tmp_publickeydata)
LIBSSH2_FREE(session, pubkeydata); LIBSSH2_FREE(session, tmp_publickeydata);
if(sk_info.application) { if(sk_info.application) {
LIBSSH2_FREE(session, (void *)sk_info.application); LIBSSH2_FREE(session, (void *)sk_info.application);