Add callback-based API for publickey auth.
Signed-off-by: Simon Josefsson <simon@josefsson.org>
This commit is contained in:
parent
0a3b350012
commit
58abc7e30b
@ -178,6 +178,11 @@ typedef struct _LIBSSH2_USERAUTH_KBDINT_RESPONSE
|
||||
unsigned int length;
|
||||
} LIBSSH2_USERAUTH_KBDINT_RESPONSE;
|
||||
|
||||
/* 'publickey' authentication callback */
|
||||
#define LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC(name) \
|
||||
int name(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, \
|
||||
const unsigned char *data, size_t data_len, void **abstract)
|
||||
|
||||
/* 'keyboard-interactive' authentication callback */
|
||||
#define LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC(name_) \
|
||||
void name_(const char* name, int name_len, const char* instruction, \
|
||||
@ -436,6 +441,14 @@ libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session,
|
||||
strlen(username), (publickey), \
|
||||
(privatekey), (passphrase))
|
||||
|
||||
LIBSSH2_API int
|
||||
libssh2_userauth_publickey(LIBSSH2_SESSION *session,
|
||||
const char *username,
|
||||
const unsigned char *pubkeydata,
|
||||
size_t pubkeydata_len,
|
||||
LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC((*sign_callback)),
|
||||
void **abstract);
|
||||
|
||||
LIBSSH2_API int
|
||||
libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session,
|
||||
const char *username,
|
||||
|
196
src/userauth.c
196
src/userauth.c
@ -615,6 +615,45 @@ file_read_privatekey(LIBSSH2_SESSION * session,
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct privkey_file {
|
||||
const char *filename;
|
||||
const char *passphrase;
|
||||
};
|
||||
|
||||
static int
|
||||
sign_fromfile(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len,
|
||||
const unsigned char *data, size_t data_len, void **abstract)
|
||||
{
|
||||
struct privkey_file *privkey_file = (struct privkey_file *) (*abstract);
|
||||
const LIBSSH2_HOSTKEY_METHOD *privkeyobj;
|
||||
void *hostkey_abstract;
|
||||
struct iovec datavec;
|
||||
|
||||
if (file_read_privatekey(session, &privkeyobj, &hostkey_abstract,
|
||||
session->userauth_pblc_method,
|
||||
session->userauth_pblc_method_len,
|
||||
privkey_file->filename,
|
||||
privkey_file->passphrase)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
datavec.iov_base = (unsigned char *)data;
|
||||
datavec.iov_len = data_len;
|
||||
|
||||
if (privkeyobj->signv(session, sig, sig_len, 1, &datavec,
|
||||
&hostkey_abstract)) {
|
||||
if (privkeyobj->dtor) {
|
||||
privkeyobj->dtor(session, abstract);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (privkeyobj->dtor) {
|
||||
privkeyobj->dtor(session, &hostkey_abstract);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* userauth_hostbased_fromfile
|
||||
@ -887,19 +926,15 @@ libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session,
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* userauth_publickey_fromfile
|
||||
* Authenticate using a keypair found in the named files
|
||||
*/
|
||||
static int
|
||||
userauth_publickey_fromfile(LIBSSH2_SESSION *session,
|
||||
const char *username,
|
||||
unsigned int username_len,
|
||||
const char *publickey,
|
||||
const char *privatekey,
|
||||
const char *passphrase)
|
||||
userauth_publickey(LIBSSH2_SESSION *session,
|
||||
const char *username,
|
||||
unsigned int username_len,
|
||||
const unsigned char *pubkeydata,
|
||||
unsigned long pubkeydata_len,
|
||||
LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC((*sign_callback)),
|
||||
void *abstract)
|
||||
{
|
||||
unsigned long pubkeydata_len = 0;
|
||||
unsigned char reply_codes[4] =
|
||||
{ SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE,
|
||||
SSH_MSG_USERAUTH_PK_OK, 0
|
||||
@ -907,17 +942,20 @@ userauth_publickey_fromfile(LIBSSH2_SESSION *session,
|
||||
int rc;
|
||||
|
||||
if (session->userauth_pblc_state == libssh2_NB_state_idle) {
|
||||
unsigned char *pubkeydata;
|
||||
|
||||
/* Zero the whole thing out */
|
||||
memset(&session->userauth_pblc_packet_requirev_state, 0,
|
||||
sizeof(session->userauth_pblc_packet_requirev_state));
|
||||
|
||||
if (file_read_publickey(session, &session->userauth_pblc_method,
|
||||
&session->userauth_pblc_method_len,
|
||||
&pubkeydata, &pubkeydata_len,publickey)) {
|
||||
session->userauth_pblc_method_len = _libssh2_ntohu32(pubkeydata);
|
||||
session->userauth_pblc_method =
|
||||
LIBSSH2_ALLOC(session, session->userauth_pblc_method_len);
|
||||
if (!session->userauth_pblc_method) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||
"Unable to allocate memory for public key data", 0);
|
||||
return -1;
|
||||
}
|
||||
memcpy(session->userauth_pblc_method, pubkeydata + 4,
|
||||
session->userauth_pblc_method_len);
|
||||
|
||||
/*
|
||||
* 45 = packet_type(1) + username_len(4) + servicename_len(4) +
|
||||
@ -942,7 +980,6 @@ userauth_publickey_fromfile(LIBSSH2_SESSION *session,
|
||||
if (!session->userauth_pblc_packet) {
|
||||
LIBSSH2_FREE(session, session->userauth_pblc_method);
|
||||
session->userauth_pblc_method = NULL;
|
||||
LIBSSH2_FREE(session, pubkeydata);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -977,7 +1014,6 @@ userauth_publickey_fromfile(LIBSSH2_SESSION *session,
|
||||
session->userauth_pblc_s += 4;
|
||||
memcpy(session->userauth_pblc_s, pubkeydata, pubkeydata_len);
|
||||
session->userauth_pblc_s += pubkeydata_len;
|
||||
LIBSSH2_FREE(session, pubkeydata);
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_AUTH,
|
||||
"Attempting publickey authentication");
|
||||
@ -1005,13 +1041,6 @@ userauth_publickey_fromfile(LIBSSH2_SESSION *session,
|
||||
}
|
||||
|
||||
if (session->userauth_pblc_state == libssh2_NB_state_sent) {
|
||||
const LIBSSH2_HOSTKEY_METHOD *privkeyobj;
|
||||
void *abstract;
|
||||
unsigned char buf[5];
|
||||
struct iovec datavec[4];
|
||||
unsigned char *sig;
|
||||
unsigned long sig_len;
|
||||
|
||||
rc = _libssh2_packet_requirev(session, reply_codes,
|
||||
&session->userauth_pblc_data,
|
||||
&session->userauth_pblc_data_len, 0,
|
||||
@ -1065,44 +1094,45 @@ userauth_publickey_fromfile(LIBSSH2_SESSION *session,
|
||||
LIBSSH2_FREE(session, session->userauth_pblc_data);
|
||||
session->userauth_pblc_data = NULL;
|
||||
|
||||
if (file_read_privatekey(session, &privkeyobj, &abstract,
|
||||
session->userauth_pblc_method,
|
||||
session->userauth_pblc_method_len,
|
||||
privatekey, passphrase)) {
|
||||
LIBSSH2_FREE(session, session->userauth_pblc_method);
|
||||
session->userauth_pblc_method = NULL;
|
||||
LIBSSH2_FREE(session, session->userauth_pblc_packet);
|
||||
session->userauth_pblc_packet = NULL;
|
||||
session->userauth_pblc_state = libssh2_NB_state_idle;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*session->userauth_pblc_b = 0x01;
|
||||
session->userauth_pblc_state = libssh2_NB_state_sent1;
|
||||
}
|
||||
|
||||
_libssh2_htonu32(buf, session->session_id_len);
|
||||
datavec[0].iov_base = buf;
|
||||
datavec[0].iov_len = 4;
|
||||
datavec[1].iov_base = session->session_id;
|
||||
datavec[1].iov_len = session->session_id_len;
|
||||
datavec[2].iov_base = session->userauth_pblc_packet;
|
||||
datavec[2].iov_len = session->userauth_pblc_packet_len;
|
||||
if (session->userauth_pblc_state == libssh2_NB_state_sent1) {
|
||||
unsigned char *buf, *s;
|
||||
unsigned char *sig;
|
||||
unsigned long sig_len;
|
||||
|
||||
if (privkeyobj->signv(session, &sig, &sig_len, 3, datavec, &abstract)) {
|
||||
s = buf = LIBSSH2_ALLOC(session, 4 + session->session_id_len
|
||||
+ session->userauth_pblc_packet_len);
|
||||
if (!buf) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||
"Unable to allocate memory for userauth-publickey "
|
||||
"signed data", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
_libssh2_htonu32(s, session->session_id_len);
|
||||
s += 4;
|
||||
memcpy (s, session->session_id, session->session_id_len);
|
||||
s += session->session_id_len;
|
||||
memcpy (s, session->userauth_pblc_packet,
|
||||
session->userauth_pblc_packet_len);
|
||||
s += session->userauth_pblc_packet_len;
|
||||
|
||||
rc = sign_callback(session, &sig, &sig_len, buf, s - buf, abstract);
|
||||
LIBSSH2_FREE(session, buf);
|
||||
if (rc == PACKET_EAGAIN) {
|
||||
return rc;
|
||||
} else if (rc) {
|
||||
LIBSSH2_FREE(session, session->userauth_pblc_method);
|
||||
session->userauth_pblc_method = NULL;
|
||||
LIBSSH2_FREE(session, session->userauth_pblc_packet);
|
||||
session->userauth_pblc_packet = NULL;
|
||||
if (privkeyobj->dtor) {
|
||||
privkeyobj->dtor(session, &abstract);
|
||||
}
|
||||
session->userauth_pblc_state = libssh2_NB_state_idle;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (privkeyobj->dtor) {
|
||||
privkeyobj->dtor(session, &abstract);
|
||||
}
|
||||
|
||||
/*
|
||||
* If this function was restarted, pubkeydata_len might still be 0
|
||||
* which will cause an unnecessary but harmless realloc here.
|
||||
@ -1157,10 +1187,10 @@ userauth_publickey_fromfile(LIBSSH2_SESSION *session,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_AUTH,
|
||||
"Attempting publickey authentication -- phase 2");
|
||||
|
||||
session->userauth_pblc_state = libssh2_NB_state_sent1;
|
||||
session->userauth_pblc_state = libssh2_NB_state_sent2;
|
||||
}
|
||||
|
||||
if (session->userauth_pblc_state == libssh2_NB_state_sent1) {
|
||||
if (session->userauth_pblc_state == libssh2_NB_state_sent2) {
|
||||
rc = _libssh2_transport_write(session, session->userauth_pblc_packet,
|
||||
session->userauth_pblc_s -
|
||||
session->userauth_pblc_packet);
|
||||
@ -1177,7 +1207,7 @@ userauth_publickey_fromfile(LIBSSH2_SESSION *session,
|
||||
LIBSSH2_FREE(session, session->userauth_pblc_packet);
|
||||
session->userauth_pblc_packet = NULL;
|
||||
|
||||
session->userauth_pblc_state = libssh2_NB_state_sent2;
|
||||
session->userauth_pblc_state = libssh2_NB_state_sent3;
|
||||
}
|
||||
|
||||
/* PK_OK is no longer valid */
|
||||
@ -1216,6 +1246,43 @@ userauth_publickey_fromfile(LIBSSH2_SESSION *session,
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* userauth_publickey_fromfile
|
||||
* Authenticate using a keypair found in the named files
|
||||
*/
|
||||
static int
|
||||
userauth_publickey_fromfile(LIBSSH2_SESSION *session,
|
||||
const char *username,
|
||||
unsigned int username_len,
|
||||
const char *publickey,
|
||||
const char *privatekey,
|
||||
const char *passphrase)
|
||||
{
|
||||
unsigned char *pubkeydata = NULL;
|
||||
unsigned long pubkeydata_len = 0;
|
||||
struct privkey_file privkey_file;
|
||||
void *abstract = &privkey_file;
|
||||
int rc;
|
||||
|
||||
privkey_file.filename = privatekey;
|
||||
privkey_file.passphrase = passphrase;
|
||||
|
||||
if (session->userauth_pblc_state == libssh2_NB_state_idle) {
|
||||
if (file_read_publickey(session, &session->userauth_pblc_method,
|
||||
&session->userauth_pblc_method_len,
|
||||
&pubkeydata, &pubkeydata_len, publickey)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
rc = userauth_publickey(session, username, username_len,
|
||||
pubkeydata, pubkeydata_len,
|
||||
sign_fromfile, &abstract);
|
||||
LIBSSH2_FREE(session, pubkeydata);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* libssh2_userauth_publickey_fromfile_ex
|
||||
* Authenticate using a keypair found in the named files
|
||||
*/
|
||||
@ -1235,6 +1302,25 @@ libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session,
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* libssh2_userauth_publickey_ex
|
||||
* Authenticate using an external callback function
|
||||
*/
|
||||
LIBSSH2_API int
|
||||
libssh2_userauth_publickey(LIBSSH2_SESSION *session,
|
||||
const char *user,
|
||||
const unsigned char *pubkeydata,
|
||||
size_t pubkeydata_len,
|
||||
LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC((*sign_callback)),
|
||||
void **abstract)
|
||||
{
|
||||
int rc;
|
||||
BLOCK_ADJUST(rc, session,
|
||||
userauth_publickey(session, user, strlen(user),
|
||||
pubkeydata, pubkeydata_len,
|
||||
sign_callback, abstract));
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user