Add callback-based API for publickey auth.

Signed-off-by: Simon Josefsson <simon@josefsson.org>
This commit is contained in:
Daiki Ueno 2009-12-16 08:46:06 +09:00 committed by Simon Josefsson
parent 0a3b350012
commit 58abc7e30b
2 changed files with 154 additions and 55 deletions

View File

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

View File

@ -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;
}
/*