mirror of
https://github.com/libssh2/libssh2.git
synced 2025-07-29 13:01:14 +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:
@ -10,6 +10,7 @@ dist_man_MANS = \
|
||||
libssh2_agent_init.3 \
|
||||
libssh2_agent_list_identities.3 \
|
||||
libssh2_agent_set_identity_path.3 \
|
||||
libssh2_agent_sign.3 \
|
||||
libssh2_agent_userauth.3 \
|
||||
libssh2_banner_set.3 \
|
||||
libssh2_base64_decode.3 \
|
||||
|
52
docs/libssh2_agent_sign.3
Normal file
52
docs/libssh2_agent_sign.3
Normal 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)
|
@ -30,3 +30,4 @@ Added in libssh2 1.2
|
||||
.SH SEE ALSO
|
||||
.BR libssh2_agent_init(3)
|
||||
.BR libssh2_agent_get_identity(3)
|
||||
.BR libssh2_agent_sign(3)
|
||||
|
@ -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
|
||||
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.
|
||||
.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
|
||||
Pointer to previous callback handler. Returns NULL if no prior callback
|
||||
handler was set or the callback type was unknown.
|
||||
.SH SEE ALSO
|
||||
.BR libssh2_session_init_ex(3)
|
||||
.BR libssh2_agent_sign(3)
|
||||
|
@ -9,6 +9,8 @@ int
|
||||
libssh2_userauth_publickey_sk(LIBSSH2_SESSION *session,
|
||||
const char *username,
|
||||
size_t username_len,
|
||||
const unsigned char *publickeydata,
|
||||
size_t publickeydata_len,
|
||||
const char *privatekeydata,
|
||||
size_t privatekeydata_len,
|
||||
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.
|
||||
|
||||
\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_len\fP - Length of private key data.
|
||||
|
@ -333,6 +333,22 @@ typedef struct _LIBSSH2_SK_SIG_INFO {
|
||||
void name(LIBSSH2_SESSION *session, LIBSSH2_CHANNEL *channel, \
|
||||
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) \
|
||||
void name(LIBSSH2_SESSION *session, void **session_abstract, \
|
||||
LIBSSH2_CHANNEL *channel, void **channel_abstract)
|
||||
@ -348,13 +364,16 @@ typedef struct _LIBSSH2_SK_SIG_INFO {
|
||||
int flags, void **abstract)
|
||||
|
||||
/* libssh2_session_callback_set() constants */
|
||||
#define LIBSSH2_CALLBACK_IGNORE 0
|
||||
#define LIBSSH2_CALLBACK_DEBUG 1
|
||||
#define LIBSSH2_CALLBACK_DISCONNECT 2
|
||||
#define LIBSSH2_CALLBACK_MACERROR 3
|
||||
#define LIBSSH2_CALLBACK_X11 4
|
||||
#define LIBSSH2_CALLBACK_SEND 5
|
||||
#define LIBSSH2_CALLBACK_RECV 6
|
||||
#define LIBSSH2_CALLBACK_IGNORE 0
|
||||
#define LIBSSH2_CALLBACK_DEBUG 1
|
||||
#define LIBSSH2_CALLBACK_DISCONNECT 2
|
||||
#define LIBSSH2_CALLBACK_MACERROR 3
|
||||
#define LIBSSH2_CALLBACK_X11 4
|
||||
#define LIBSSH2_CALLBACK_SEND 5
|
||||
#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 */
|
||||
#define LIBSSH2_METHOD_KEX 0
|
||||
@ -747,6 +766,8 @@ LIBSSH2_API int
|
||||
libssh2_userauth_publickey_sk(LIBSSH2_SESSION *session,
|
||||
const char *username,
|
||||
size_t username_len,
|
||||
const unsigned char *pubkeydata,
|
||||
size_t pubkeydata_len,
|
||||
const char *privatekeydata,
|
||||
size_t privatekeydata_len,
|
||||
const char *passphrase,
|
||||
@ -1331,6 +1352,23 @@ libssh2_agent_userauth(LIBSSH2_AGENT *agent,
|
||||
const char *username,
|
||||
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()
|
||||
*
|
||||
|
60
src/agent.c
60
src/agent.c
@ -383,6 +383,7 @@ agent_sign(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len,
|
||||
int rc;
|
||||
unsigned char *method_name = NULL;
|
||||
uint32_t sign_flags = 0;
|
||||
ssize_t plain_len;
|
||||
|
||||
/* Create a request to sign the data */
|
||||
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);
|
||||
s += method_len;
|
||||
|
||||
plain_len = plain_method((char *)session->userauth_pblc_method,
|
||||
session->userauth_pblc_method_len);
|
||||
|
||||
/* check to see if we match requested */
|
||||
if((size_t)method_len != session->userauth_pblc_method_len ||
|
||||
memcmp(method_name, session->userauth_pblc_method, method_len)) {
|
||||
if(((size_t)method_len != session->userauth_pblc_method_len &&
|
||||
method_len != plain_len) ||
|
||||
memcmp(method_name, session->userauth_pblc_method, method_len)) {
|
||||
_libssh2_debug((session,
|
||||
LIBSSH2_TRACE_KEX,
|
||||
"Agent sign method %.*s",
|
||||
@ -829,6 +834,57 @@ libssh2_agent_userauth(LIBSSH2_AGENT *agent,
|
||||
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
|
||||
*
|
||||
|
@ -1257,6 +1257,18 @@ static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_ed25519 = {
|
||||
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 */
|
||||
|
||||
|
||||
@ -1271,6 +1283,7 @@ static const LIBSSH2_HOSTKEY_METHOD *hostkey_methods[] = {
|
||||
#endif
|
||||
#if LIBSSH2_ED25519
|
||||
&hostkey_method_ssh_ed25519,
|
||||
&hostkey_method_ssh_ed25519_cert,
|
||||
#endif
|
||||
#if LIBSSH2_RSA
|
||||
#if LIBSSH2_RSA_SHA2
|
||||
|
@ -199,6 +199,21 @@ struct iovec {
|
||||
channel->session->x11(((channel)->session), (channel), \
|
||||
(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) \
|
||||
channel->close_cb((session), &(session)->abstract, \
|
||||
(channel), &(channel)->abstract)
|
||||
@ -238,7 +253,8 @@ typedef enum
|
||||
libssh2_NB_state_jump3,
|
||||
libssh2_NB_state_jump4,
|
||||
libssh2_NB_state_jump5,
|
||||
libssh2_NB_state_end
|
||||
libssh2_NB_state_end,
|
||||
libssh2_NB_state_jumpauthagent
|
||||
} libssh2_nonblocking_states;
|
||||
|
||||
typedef struct packet_require_state_t
|
||||
@ -344,6 +360,24 @@ typedef struct packet_x11_open_state_t
|
||||
LIBSSH2_CHANNEL *channel;
|
||||
} 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 list_node node; /* linked list header */
|
||||
@ -518,7 +552,7 @@ typedef struct _libssh2_endpoint_data
|
||||
char *lang_prefs;
|
||||
} libssh2_endpoint_data;
|
||||
|
||||
#define PACKETBUFSIZE (1024*16)
|
||||
#define PACKETBUFSIZE MAX_SSH_PACKET_LEN
|
||||
|
||||
struct transportpacket
|
||||
{
|
||||
@ -606,6 +640,9 @@ struct _LIBSSH2_SESSION
|
||||
LIBSSH2_DISCONNECT_FUNC((*ssh_msg_disconnect));
|
||||
LIBSSH2_MACERROR_FUNC((*macerror));
|
||||
LIBSSH2_X11_OPEN_FUNC((*x11));
|
||||
LIBSSH2_AUTHAGENT_FUNC((*authagent));
|
||||
LIBSSH2_ADD_IDENTITIES_FUNC((*addLocalIdentities));
|
||||
LIBSSH2_AUTHAGENT_SIGN_FUNC((*agentSignCallback));
|
||||
LIBSSH2_SEND_FUNC((*send));
|
||||
LIBSSH2_RECV_FUNC((*recv));
|
||||
|
||||
@ -820,6 +857,7 @@ struct _LIBSSH2_SESSION
|
||||
states */
|
||||
packet_queue_listener_state_t packAdd_Qlstn_state;
|
||||
packet_x11_open_state_t packAdd_x11open_state;
|
||||
packet_authagent_state_t packAdd_authagent_state;
|
||||
|
||||
/* State variables used in fullpacket() */
|
||||
libssh2_nonblocking_states fullpacket_state;
|
||||
@ -1151,6 +1189,8 @@ int _libssh2_pem_decode_integer(unsigned char **data, size_t *datalen,
|
||||
/* global.c */
|
||||
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]))
|
||||
|
||||
|
164
src/packet.c
164
src/packet.c
@ -460,6 +460,154 @@ packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
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
|
||||
*
|
||||
@ -513,6 +661,8 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
goto libssh2_packet_add_jump_point4;
|
||||
case libssh2_NB_state_jump5:
|
||||
goto libssh2_packet_add_jump_point5;
|
||||
case libssh2_NB_state_jumpauthagent:
|
||||
goto libssh2_packet_add_jump_authagent;
|
||||
default: /* nothing to do */
|
||||
break;
|
||||
}
|
||||
@ -1051,6 +1201,20 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
rc = packet_x11_open(session, data, datalen,
|
||||
&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)
|
||||
return rc;
|
||||
|
||||
|
@ -536,6 +536,21 @@ libssh2_session_callback_set(LIBSSH2_SESSION * session,
|
||||
oldcb = session->recv;
|
||||
session->recv = callback;
|
||||
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",
|
||||
cbtype));
|
||||
|
107
src/userauth.c
107
src/userauth.c
@ -1249,7 +1249,7 @@ libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session,
|
||||
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",
|
||||
method,
|
||||
@ -1268,6 +1268,29 @@ static size_t plain_method_len(const char *method, size_t method_len)
|
||||
method_len)) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1701,8 +1724,8 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session,
|
||||
session->userauth_pblc_b = NULL;
|
||||
|
||||
session->userauth_pblc_method_len =
|
||||
plain_method_len((const char *)session->userauth_pblc_method,
|
||||
session->userauth_pblc_method_len);
|
||||
plain_method((char *)session->userauth_pblc_method,
|
||||
session->userauth_pblc_method_len);
|
||||
|
||||
if(strncmp((const char *)session->userauth_pblc_method,
|
||||
"sk-ecdsa-sha2-nistp256@openssh.com",
|
||||
@ -2291,6 +2314,8 @@ LIBSSH2_API int
|
||||
libssh2_userauth_publickey_sk(LIBSSH2_SESSION *session,
|
||||
const char *username,
|
||||
size_t username_len,
|
||||
const unsigned char *publickeydata,
|
||||
size_t publickeydata_len,
|
||||
const char *privatekeydata,
|
||||
size_t privatekeydata_len,
|
||||
const char *passphrase,
|
||||
@ -2298,11 +2323,19 @@ libssh2_userauth_publickey_sk(LIBSSH2_SESSION *session,
|
||||
((*sign_callback)),
|
||||
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;
|
||||
size_t pubkeydata_len = 0;
|
||||
|
||||
LIBSSH2_PRIVKEY_SK sk_info = { 0 };
|
||||
void *sign_abstract = &sk_info;
|
||||
int rc;
|
||||
|
||||
sk_info.sign_callback = sign_callback;
|
||||
sk_info.orig_abstract = abstract;
|
||||
@ -2310,37 +2343,81 @@ libssh2_userauth_publickey_sk(LIBSSH2_SESSION *session,
|
||||
if(privatekeydata_len && privatekeydata) {
|
||||
|
||||
if(_libssh2_sk_pub_keyfilememory(session,
|
||||
&session->userauth_pblc_method,
|
||||
&session->userauth_pblc_method_len,
|
||||
&pubkeydata, &pubkeydata_len,
|
||||
&tmp_method,
|
||||
&tmp_method_len,
|
||||
&tmp_publickeydata,
|
||||
&tmp_publickeydata_len,
|
||||
&(sk_info.algorithm),
|
||||
&(sk_info.flags),
|
||||
&(sk_info.application),
|
||||
&(sk_info.key_handle),
|
||||
&(sk_info.handle_len),
|
||||
privatekeydata, privatekeydata_len,
|
||||
passphrase))
|
||||
passphrase)) {
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_FILE,
|
||||
"Unable to extract public 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 {
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_FILE,
|
||||
"Invalid data in public and private key.");
|
||||
}
|
||||
|
||||
rc = _libssh2_userauth_publickey(session, username, username_len,
|
||||
pubkeydata, pubkeydata_len,
|
||||
libssh2_sign_sk, &sign_abstract);
|
||||
|
||||
while(rc == LIBSSH2_ERROR_EAGAIN) {
|
||||
if(rc == LIBSSH2_ERROR_NONE) {
|
||||
rc = _libssh2_userauth_publickey(session, username, username_len,
|
||||
pubkeydata, pubkeydata_len,
|
||||
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)
|
||||
LIBSSH2_FREE(session, pubkeydata);
|
||||
if(tmp_publickeydata)
|
||||
LIBSSH2_FREE(session, tmp_publickeydata);
|
||||
|
||||
if(sk_info.application) {
|
||||
LIBSSH2_FREE(session, (void *)sk_info.application);
|
||||
|
Reference in New Issue
Block a user