1
0
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:
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_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
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
.BR libssh2_agent_init(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
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)

View File

@ -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.

View File

@ -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()
*

View File

@ -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
*

View File

@ -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

View File

@ -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]))

View File

@ -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;

View File

@ -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));

View File

@ -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);