Allow authentication keys to be passed in memory.
All credits go to Joe Turpin, I'm just reaplying and cleaning his patch: http://www.libssh2.org/mail/libssh2-devel-archive-2012-01/0015.shtml * Use an unimplemented error for extracting keys from memory with libgcrypt.
Этот коммит содержится в:
родитель
74624c8ddf
Коммит
18cfec8336
57
docs/libssh2_userauth_publickey_frommemory.3
Обычный файл
57
docs/libssh2_userauth_publickey_frommemory.3
Обычный файл
@ -0,0 +1,57 @@
|
|||||||
|
.TH libssh2_userauth_publickey_frommemory 3 "1 Sep 2014" "libssh2 1.5" "libssh2 manual"
|
||||||
|
.SH NAME
|
||||||
|
libssh2_userauth_publickey_frommemory - authenticate a session with a public key, read from memory
|
||||||
|
.SH SYNOPSIS
|
||||||
|
#include <libssh2.h>
|
||||||
|
|
||||||
|
.nf
|
||||||
|
int libssh2_userauth_publickey_frommemory(LIBSSH2_SESSION *session,
|
||||||
|
const char *username,
|
||||||
|
size_t username_len,
|
||||||
|
const char *publickeydata,
|
||||||
|
size_t publickeydata_len,
|
||||||
|
const char *privatekeydata,
|
||||||
|
size_t privatekeydata_len,
|
||||||
|
const char *passphrase);
|
||||||
|
.SH DESCRIPTION
|
||||||
|
This function allows to authenticate a session with a public key read from memory.
|
||||||
|
It's only supported when libssh2 is backed by OpenSSL.
|
||||||
|
\fIsession\fP - Session instance as returned by
|
||||||
|
.BR libssh2_session_init_ex(3)
|
||||||
|
|
||||||
|
\fIusername\fP - Remote user name to authenticate as.
|
||||||
|
|
||||||
|
\fIusername_len\fP - Length of username.
|
||||||
|
|
||||||
|
\fIpublickeydata\fP - Buffer containing the contents of a public key file.
|
||||||
|
|
||||||
|
\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.
|
||||||
|
|
||||||
|
\fIpassphrase\fP - Passphrase to use when decoding private key file.
|
||||||
|
|
||||||
|
Attempt public key authentication using a PEM encoded private key file stored in memory.
|
||||||
|
|
||||||
|
.SH RETURN VALUE
|
||||||
|
Return 0 on success or negative on failure. It returns
|
||||||
|
LIBSSH2_ERROR_EAGAIN when it would otherwise block. While
|
||||||
|
LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
|
||||||
|
|
||||||
|
.SH ERRORS
|
||||||
|
\fILIBSSH2_ERROR_ALLOC\fP - An internal memory allocation call failed.
|
||||||
|
|
||||||
|
\fILIBSSH2_ERROR_SOCKET_SEND\fP - Unable to send data on socket.
|
||||||
|
|
||||||
|
\fILIBSSH2_ERROR_SOCKET_TIMEOUT\fP -
|
||||||
|
|
||||||
|
\fILIBSSH2_ERROR_PUBLICKEY_UNVERIFIED\fP - The username/public key
|
||||||
|
combination was invalid.
|
||||||
|
|
||||||
|
\fILIBSSH2_ERROR_AUTHENTICATION_FAILED\fP - Authentication using the supplied
|
||||||
|
public key was not accepted.
|
||||||
|
|
||||||
|
.SH SEE ALSO
|
||||||
|
.BR libssh2_session_init_ex(3)
|
@ -576,6 +576,16 @@ libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session,
|
|||||||
(username), \
|
(username), \
|
||||||
(unsigned int)strlen(username))
|
(unsigned int)strlen(username))
|
||||||
|
|
||||||
|
LIBSSH2_API int
|
||||||
|
libssh2_userauth_publickey_frommemory(LIBSSH2_SESSION *session,
|
||||||
|
const char *username,
|
||||||
|
size_t username_len,
|
||||||
|
const char *publickeyfiledata,
|
||||||
|
size_t publickeyfiledata_len,
|
||||||
|
const char *privatekeyfiledata,
|
||||||
|
size_t privatekeyfiledata_len,
|
||||||
|
const char *passphrase);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* response_callback is provided with filled by library prompts array,
|
* response_callback is provided with filled by library prompts array,
|
||||||
* but client must allocate and fill individual responses. Responses
|
* but client must allocate and fill individual responses. Responses
|
||||||
|
16
src/crypto.h
16
src/crypto.h
@ -80,6 +80,10 @@ int _libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session,
|
|||||||
size_t hash_len,
|
size_t hash_len,
|
||||||
unsigned char **signature,
|
unsigned char **signature,
|
||||||
size_t *signature_len);
|
size_t *signature_len);
|
||||||
|
int _libssh2_rsa_new_private_frommemory(libssh2_rsa_ctx ** rsa,
|
||||||
|
LIBSSH2_SESSION * session,
|
||||||
|
const char *filedata, size_t filedata_len,
|
||||||
|
unsigned const char *passphrase);
|
||||||
|
|
||||||
#if LIBSSH2_DSA
|
#if LIBSSH2_DSA
|
||||||
int _libssh2_dsa_new(libssh2_dsa_ctx ** dsa,
|
int _libssh2_dsa_new(libssh2_dsa_ctx ** dsa,
|
||||||
@ -102,6 +106,10 @@ int _libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx,
|
|||||||
int _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx,
|
int _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx,
|
||||||
const unsigned char *hash,
|
const unsigned char *hash,
|
||||||
unsigned long hash_len, unsigned char *sig);
|
unsigned long hash_len, unsigned char *sig);
|
||||||
|
int _libssh2_dsa_new_private_frommemory(libssh2_dsa_ctx ** dsa,
|
||||||
|
LIBSSH2_SESSION * session,
|
||||||
|
const char *filedata, size_t filedata_len,
|
||||||
|
unsigned const char *passphrase);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int _libssh2_cipher_init(_libssh2_cipher_ctx * h,
|
int _libssh2_cipher_init(_libssh2_cipher_ctx * h,
|
||||||
@ -120,6 +128,14 @@ int _libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session,
|
|||||||
size_t *pubkeydata_len,
|
size_t *pubkeydata_len,
|
||||||
const char *privatekey,
|
const char *privatekey,
|
||||||
const char *passphrase);
|
const char *passphrase);
|
||||||
|
int _libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session,
|
||||||
|
unsigned char **method,
|
||||||
|
size_t *method_len,
|
||||||
|
unsigned char **pubkeydata,
|
||||||
|
size_t *pubkeydata_len,
|
||||||
|
const char *privatekeydata,
|
||||||
|
size_t privatekeydata_len,
|
||||||
|
const char *passphrase);
|
||||||
|
|
||||||
void _libssh2_init_aes_ctr(void);
|
void _libssh2_init_aes_ctr(void);
|
||||||
|
|
||||||
|
@ -130,6 +130,38 @@ hostkey_method_ssh_rsa_initPEM(LIBSSH2_SESSION * session,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* hostkey_method_ssh_rsa_initPEMFromMemory
|
||||||
|
*
|
||||||
|
* Load a Private Key from a memory
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
hostkey_method_ssh_rsa_initPEMFromMemory(LIBSSH2_SESSION * session,
|
||||||
|
const char *privkeyfiledata,
|
||||||
|
size_t privkeyfiledata_len,
|
||||||
|
unsigned const char *passphrase,
|
||||||
|
void **abstract)
|
||||||
|
{
|
||||||
|
libssh2_rsa_ctx *rsactx;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (*abstract) {
|
||||||
|
hostkey_method_ssh_rsa_dtor(session, abstract);
|
||||||
|
*abstract = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = _libssh2_rsa_new_private_frommemory(&rsactx, session,
|
||||||
|
privkeyfiledata,
|
||||||
|
privkeyfiledata_len, passphrase);
|
||||||
|
if (ret) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*abstract = rsactx;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* hostkey_method_ssh_rsa_sign
|
* hostkey_method_ssh_rsa_sign
|
||||||
*
|
*
|
||||||
@ -208,6 +240,7 @@ static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_rsa = {
|
|||||||
MD5_DIGEST_LENGTH,
|
MD5_DIGEST_LENGTH,
|
||||||
hostkey_method_ssh_rsa_init,
|
hostkey_method_ssh_rsa_init,
|
||||||
hostkey_method_ssh_rsa_initPEM,
|
hostkey_method_ssh_rsa_initPEM,
|
||||||
|
hostkey_method_ssh_rsa_initPEMFromMemory,
|
||||||
hostkey_method_ssh_rsa_sig_verify,
|
hostkey_method_ssh_rsa_sig_verify,
|
||||||
hostkey_method_ssh_rsa_signv,
|
hostkey_method_ssh_rsa_signv,
|
||||||
NULL, /* encrypt */
|
NULL, /* encrypt */
|
||||||
@ -305,6 +338,38 @@ hostkey_method_ssh_dss_initPEM(LIBSSH2_SESSION * session,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* hostkey_method_ssh_dss_initPEMFromMemory
|
||||||
|
*
|
||||||
|
* Load a Private Key from memory
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
hostkey_method_ssh_dss_initPEMFromMemory(LIBSSH2_SESSION * session,
|
||||||
|
const char *privkeyfiledata,
|
||||||
|
size_t privkeyfiledata_len,
|
||||||
|
unsigned const char *passphrase,
|
||||||
|
void **abstract)
|
||||||
|
{
|
||||||
|
libssh2_dsa_ctx *dsactx;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (*abstract) {
|
||||||
|
hostkey_method_ssh_dss_dtor(session, abstract);
|
||||||
|
*abstract = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = _libssh2_dsa_new_private_frommemory(&dsactx, session,
|
||||||
|
privkeyfiledata,
|
||||||
|
privkeyfiledata_len, passphrase);
|
||||||
|
if (ret) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*abstract = dsactx;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* libssh2_hostkey_method_ssh_dss_sign
|
* libssh2_hostkey_method_ssh_dss_sign
|
||||||
*
|
*
|
||||||
@ -391,6 +456,7 @@ static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_dss = {
|
|||||||
MD5_DIGEST_LENGTH,
|
MD5_DIGEST_LENGTH,
|
||||||
hostkey_method_ssh_dss_init,
|
hostkey_method_ssh_dss_init,
|
||||||
hostkey_method_ssh_dss_initPEM,
|
hostkey_method_ssh_dss_initPEM,
|
||||||
|
hostkey_method_ssh_dss_initPEMFromMemory,
|
||||||
hostkey_method_ssh_dss_sig_verify,
|
hostkey_method_ssh_dss_sig_verify,
|
||||||
hostkey_method_ssh_dss_signv,
|
hostkey_method_ssh_dss_signv,
|
||||||
NULL, /* encrypt */
|
NULL, /* encrypt */
|
||||||
|
@ -149,6 +149,17 @@ _libssh2_dsa_new(libssh2_dsa_ctx ** dsactx,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
_libssh2_rsa_new_private_frommemory(libssh2_rsa_ctx ** rsa,
|
||||||
|
LIBSSH2_SESSION * session,
|
||||||
|
const char *filedata, size_t filedata_len,
|
||||||
|
unsigned const char *passphrase)
|
||||||
|
{
|
||||||
|
return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
|
||||||
|
"Unable to extract private key from memory: "
|
||||||
|
"Method unimplemented in libgcrypt backend");
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
_libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa,
|
_libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa,
|
||||||
LIBSSH2_SESSION * session,
|
LIBSSH2_SESSION * session,
|
||||||
@ -251,6 +262,17 @@ _libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
_libssh2_dsa_new_private_frommemory(libssh2_dsa_ctx ** dsa,
|
||||||
|
LIBSSH2_SESSION * session,
|
||||||
|
const char *filedata, size_t filedata_len,
|
||||||
|
unsigned const char *passphrase)
|
||||||
|
{
|
||||||
|
return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
|
||||||
|
"Unable to extract private key from memory: "
|
||||||
|
"Method unimplemented in libgcrypt backend");
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
_libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa,
|
_libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa,
|
||||||
LIBSSH2_SESSION * session,
|
LIBSSH2_SESSION * session,
|
||||||
@ -566,6 +588,21 @@ _libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
_libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session,
|
||||||
|
unsigned char **method,
|
||||||
|
size_t *method_len,
|
||||||
|
unsigned char **pubkeydata,
|
||||||
|
size_t *pubkeydata_len,
|
||||||
|
const char *privatekeydata,
|
||||||
|
size_t privatekeydata_len,
|
||||||
|
const char *passphrase)
|
||||||
|
{
|
||||||
|
return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
|
||||||
|
"Unable to extract public key from private key in memory: "
|
||||||
|
"Method unimplemented in libgcrypt backend");
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
_libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session,
|
_libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session,
|
||||||
unsigned char **method,
|
unsigned char **method,
|
||||||
|
@ -854,6 +854,9 @@ struct _LIBSSH2_HOSTKEY_METHOD
|
|||||||
size_t hostkey_data_len, void **abstract);
|
size_t hostkey_data_len, void **abstract);
|
||||||
int (*initPEM) (LIBSSH2_SESSION * session, const char *privkeyfile,
|
int (*initPEM) (LIBSSH2_SESSION * session, const char *privkeyfile,
|
||||||
unsigned const char *passphrase, void **abstract);
|
unsigned const char *passphrase, void **abstract);
|
||||||
|
int (*initPEMFromMemory) (LIBSSH2_SESSION * session,
|
||||||
|
const char *privkeyfiledata, size_t privkeyfiledata_len,
|
||||||
|
unsigned const char *passphrase, void **abstract);
|
||||||
int (*sig_verify) (LIBSSH2_SESSION * session, const unsigned char *sig,
|
int (*sig_verify) (LIBSSH2_SESSION * session, const unsigned char *sig,
|
||||||
size_t sig_len, const unsigned char *m,
|
size_t sig_len, const unsigned char *m,
|
||||||
size_t m_len, void **abstract);
|
size_t m_len, void **abstract);
|
||||||
|
121
src/openssl.c
121
src/openssl.c
@ -387,6 +387,28 @@ passphrase_cb(char *buf, int size, int rwflag, char *passphrase)
|
|||||||
typedef void * (*pem_read_bio_func)(BIO *, void **, pem_password_cb *,
|
typedef void * (*pem_read_bio_func)(BIO *, void **, pem_password_cb *,
|
||||||
void * u);
|
void * u);
|
||||||
|
|
||||||
|
static int
|
||||||
|
read_private_key_from_memory(void ** key_ctx,
|
||||||
|
pem_read_bio_func read_private_key,
|
||||||
|
const char * filedata,
|
||||||
|
size_t filedata_len,
|
||||||
|
unsigned const char *passphrase)
|
||||||
|
{
|
||||||
|
BIO * bp;
|
||||||
|
|
||||||
|
*key_ctx = NULL;
|
||||||
|
|
||||||
|
bp = BIO_new_mem_buf(filedata, filedata_len);
|
||||||
|
if (!bp) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
*key_ctx = read_private_key(bp, NULL, (pem_password_cb *) passphrase_cb,
|
||||||
|
(void *) passphrase);
|
||||||
|
|
||||||
|
BIO_free(bp);
|
||||||
|
return (*key_ctx) ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
read_private_key_from_file(void ** key_ctx,
|
read_private_key_from_file(void ** key_ctx,
|
||||||
pem_read_bio_func read_private_key,
|
pem_read_bio_func read_private_key,
|
||||||
@ -409,6 +431,22 @@ read_private_key_from_file(void ** key_ctx,
|
|||||||
return (*key_ctx) ? 0 : -1;
|
return (*key_ctx) ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
_libssh2_rsa_new_private_frommemory(libssh2_rsa_ctx ** rsa,
|
||||||
|
LIBSSH2_SESSION * session,
|
||||||
|
const char *filedata, size_t filedata_len,
|
||||||
|
unsigned const char *passphrase)
|
||||||
|
{
|
||||||
|
pem_read_bio_func read_rsa =
|
||||||
|
(pem_read_bio_func) &PEM_read_bio_RSAPrivateKey;
|
||||||
|
(void) session;
|
||||||
|
|
||||||
|
_libssh2_init_if_needed();
|
||||||
|
|
||||||
|
return read_private_key_from_memory((void **) rsa, read_rsa,
|
||||||
|
filedata, filedata_len, passphrase);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
_libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa,
|
_libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa,
|
||||||
LIBSSH2_SESSION * session,
|
LIBSSH2_SESSION * session,
|
||||||
@ -425,6 +463,22 @@ _libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if LIBSSH2_DSA
|
#if LIBSSH2_DSA
|
||||||
|
int
|
||||||
|
_libssh2_dsa_new_private_frommemory(libssh2_dsa_ctx ** dsa,
|
||||||
|
LIBSSH2_SESSION * session,
|
||||||
|
const char *filedata, size_t filedata_len,
|
||||||
|
unsigned const char *passphrase)
|
||||||
|
{
|
||||||
|
pem_read_bio_func read_dsa =
|
||||||
|
(pem_read_bio_func) &PEM_read_bio_DSAPrivateKey;
|
||||||
|
(void) session;
|
||||||
|
|
||||||
|
_libssh2_init_if_needed();
|
||||||
|
|
||||||
|
return read_private_key_from_memory((void **) dsa, read_dsa,
|
||||||
|
filedata, filedata_len, passphrase);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
_libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa,
|
_libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa,
|
||||||
LIBSSH2_SESSION * session,
|
LIBSSH2_SESSION * session,
|
||||||
@ -817,4 +871,71 @@ _libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session,
|
|||||||
return st;
|
return st;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
_libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session,
|
||||||
|
unsigned char **method,
|
||||||
|
size_t *method_len,
|
||||||
|
unsigned char **pubkeydata,
|
||||||
|
size_t *pubkeydata_len,
|
||||||
|
const char *privatekeydata,
|
||||||
|
size_t privatekeydata_len,
|
||||||
|
const char *passphrase)
|
||||||
|
{
|
||||||
|
int st;
|
||||||
|
BIO* bp;
|
||||||
|
EVP_PKEY* pk;
|
||||||
|
|
||||||
|
_libssh2_debug(session,
|
||||||
|
LIBSSH2_TRACE_AUTH,
|
||||||
|
"Computing public key from private key.");
|
||||||
|
|
||||||
|
bp = BIO_new_mem_buf(privatekeydata, privatekeydata_len);
|
||||||
|
if (!bp) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (!EVP_get_cipherbyname("des")) {
|
||||||
|
/* If this cipher isn't loaded it's a pretty good indication that none
|
||||||
|
* are. I have *NO DOUBT* that there's a better way to deal with this
|
||||||
|
* ($#&%#$(%$#( Someone buy me an OpenSSL manual and I'll read up on
|
||||||
|
* it.
|
||||||
|
*/
|
||||||
|
OpenSSL_add_all_ciphers();
|
||||||
|
}
|
||||||
|
BIO_reset(bp);
|
||||||
|
pk = PEM_read_bio_PrivateKey(bp, NULL, NULL, (void*)passphrase);
|
||||||
|
BIO_free(bp);
|
||||||
|
|
||||||
|
if (pk == NULL) {
|
||||||
|
return _libssh2_error(session,
|
||||||
|
LIBSSH2_ERROR_FILE,
|
||||||
|
"Unable to extract public key "
|
||||||
|
"from private key file: "
|
||||||
|
"Wrong passphrase or invalid/unrecognized "
|
||||||
|
"private key file format");
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (pk->type) {
|
||||||
|
case EVP_PKEY_RSA :
|
||||||
|
st = gen_publickey_from_rsa_evp(session, method, method_len,
|
||||||
|
pubkeydata, pubkeydata_len, pk);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EVP_PKEY_DSA :
|
||||||
|
st = gen_publickey_from_dsa_evp(session, method, method_len,
|
||||||
|
pubkeydata, pubkeydata_len, pk);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default :
|
||||||
|
st = _libssh2_error(session,
|
||||||
|
LIBSSH2_ERROR_FILE,
|
||||||
|
"Unable to extract public key "
|
||||||
|
"from private key file: "
|
||||||
|
"Unsupported private key file format");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
EVP_PKEY_free(pk);
|
||||||
|
return st;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* LIBSSH2_OPENSSL */
|
#endif /* LIBSSH2_OPENSSL */
|
||||||
|
231
src/userauth.c
231
src/userauth.c
@ -442,6 +442,76 @@ libssh2_userauth_password_ex(LIBSSH2_SESSION *session, const char *username,
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
memory_read_publickey(LIBSSH2_SESSION * session, unsigned char **method,
|
||||||
|
size_t *method_len,
|
||||||
|
unsigned char **pubkeydata,
|
||||||
|
size_t *pubkeydata_len,
|
||||||
|
const char *pubkeyfiledata,
|
||||||
|
size_t pubkeyfiledata_len)
|
||||||
|
{
|
||||||
|
unsigned char *pubkey = NULL, *sp1, *sp2, *tmp;
|
||||||
|
size_t pubkey_len = pubkeyfiledata_len;
|
||||||
|
unsigned int tmp_len;
|
||||||
|
|
||||||
|
if (pubkeyfiledata_len <= 1) {
|
||||||
|
return _libssh2_error(session, LIBSSH2_ERROR_FILE,
|
||||||
|
"Invalid data in public key file");
|
||||||
|
}
|
||||||
|
|
||||||
|
pubkey = LIBSSH2_ALLOC(session, pubkeyfiledata_len);
|
||||||
|
if (!pubkey) {
|
||||||
|
return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||||
|
"Unable to allocate memory for public key data");
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(pubkey, pubkeyfiledata, pubkeyfiledata_len);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove trailing whitespace
|
||||||
|
*/
|
||||||
|
while (pubkey_len && isspace(pubkey[pubkey_len - 1]))
|
||||||
|
pubkey_len--;
|
||||||
|
|
||||||
|
if (!pubkey_len) {
|
||||||
|
LIBSSH2_FREE(session, pubkey);
|
||||||
|
return _libssh2_error(session, LIBSSH2_ERROR_FILE,
|
||||||
|
"Missing public key data");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((sp1 = memchr(pubkey, ' ', pubkey_len)) == NULL) {
|
||||||
|
LIBSSH2_FREE(session, pubkey);
|
||||||
|
return _libssh2_error(session, LIBSSH2_ERROR_FILE,
|
||||||
|
"Invalid public key data");
|
||||||
|
}
|
||||||
|
|
||||||
|
sp1++;
|
||||||
|
|
||||||
|
if ((sp2 = memchr(sp1, ' ', pubkey_len - (sp1 - pubkey - 1))) == NULL) {
|
||||||
|
/* Assume that the id string is missing, but that it's okay */
|
||||||
|
sp2 = pubkey + pubkey_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (libssh2_base64_decode(session, (char **) &tmp, &tmp_len,
|
||||||
|
(char *) sp1, sp2 - sp1)) {
|
||||||
|
LIBSSH2_FREE(session, pubkey);
|
||||||
|
return _libssh2_error(session, LIBSSH2_ERROR_FILE,
|
||||||
|
"Invalid key data, not base64 encoded");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wasting some bytes here (okay, more than some), but since it's likely
|
||||||
|
* to be freed soon anyway, we'll just avoid the extra free/alloc and call
|
||||||
|
* it a wash
|
||||||
|
*/
|
||||||
|
*method = pubkey;
|
||||||
|
*method_len = sp1 - pubkey - 1;
|
||||||
|
|
||||||
|
*pubkeydata = tmp;
|
||||||
|
*pubkeydata_len = tmp_len;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* file_read_publickey
|
* file_read_publickey
|
||||||
*
|
*
|
||||||
@ -547,7 +617,43 @@ file_read_publickey(LIBSSH2_SESSION * session, unsigned char **method,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
memory_read_privatekey(LIBSSH2_SESSION * session,
|
||||||
|
const LIBSSH2_HOSTKEY_METHOD ** hostkey_method,
|
||||||
|
void **hostkey_abstract,
|
||||||
|
const unsigned char *method, int method_len,
|
||||||
|
const char *privkeyfiledata, size_t privkeyfiledata_len,
|
||||||
|
const char *passphrase)
|
||||||
|
{
|
||||||
|
const LIBSSH2_HOSTKEY_METHOD **hostkey_methods_avail =
|
||||||
|
libssh2_hostkey_methods();
|
||||||
|
|
||||||
|
*hostkey_method = NULL;
|
||||||
|
*hostkey_abstract = NULL;
|
||||||
|
while (*hostkey_methods_avail && (*hostkey_methods_avail)->name) {
|
||||||
|
if ((*hostkey_methods_avail)->initPEMFromMemory
|
||||||
|
&& strncmp((*hostkey_methods_avail)->name, (const char *) method,
|
||||||
|
method_len) == 0) {
|
||||||
|
*hostkey_method = *hostkey_methods_avail;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
hostkey_methods_avail++;
|
||||||
|
}
|
||||||
|
if (!*hostkey_method) {
|
||||||
|
return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NONE,
|
||||||
|
"No handler for specified private key");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((*hostkey_method)->
|
||||||
|
initPEMFromMemory(session, privkeyfiledata, privkeyfiledata_len,
|
||||||
|
(unsigned char *) passphrase,
|
||||||
|
hostkey_abstract)) {
|
||||||
|
return _libssh2_error(session, LIBSSH2_ERROR_FILE,
|
||||||
|
"Unable to initialize private key from file");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* libssh2_file_read_privatekey
|
/* libssh2_file_read_privatekey
|
||||||
* Read a PEM encoded private key from an id_??? style file
|
* Read a PEM encoded private key from an id_??? style file
|
||||||
@ -595,6 +701,42 @@ struct privkey_file {
|
|||||||
const char *passphrase;
|
const char *passphrase;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
sign_frommemory(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len,
|
||||||
|
const unsigned char *data, size_t data_len, void **abstract)
|
||||||
|
{
|
||||||
|
struct privkey_file *pk_file = (struct privkey_file *) (*abstract);
|
||||||
|
const LIBSSH2_HOSTKEY_METHOD *privkeyobj;
|
||||||
|
void *hostkey_abstract;
|
||||||
|
struct iovec datavec;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = memory_read_privatekey(session, &privkeyobj, &hostkey_abstract,
|
||||||
|
session->userauth_pblc_method,
|
||||||
|
session->userauth_pblc_method_len,
|
||||||
|
pk_file->filename,
|
||||||
|
strlen(pk_file->filename),
|
||||||
|
pk_file->passphrase);
|
||||||
|
if(rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
datavec.iov_base = (void *)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;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
sign_fromfile(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len,
|
sign_fromfile(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len,
|
||||||
const unsigned char *data, size_t data_len, void **abstract)
|
const unsigned char *data, size_t data_len, void **abstract)
|
||||||
@ -1215,6 +1357,65 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session,
|
|||||||
"username/public key combination");
|
"username/public key combination");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* userauth_publickey_frommemory
|
||||||
|
* Authenticate using a keypair from memory
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
userauth_publickey_frommemory(LIBSSH2_SESSION *session,
|
||||||
|
const char *username,
|
||||||
|
size_t username_len,
|
||||||
|
const char *publickeydata,
|
||||||
|
size_t publickeydata_len,
|
||||||
|
const char *privatekeydata,
|
||||||
|
size_t privatekeydata_len,
|
||||||
|
const char *passphrase)
|
||||||
|
{
|
||||||
|
unsigned char *pubkeydata = NULL;
|
||||||
|
size_t pubkeydata_len = 0;
|
||||||
|
struct privkey_file privkey_file;
|
||||||
|
void *abstract = &privkey_file;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
privkey_file.filename = privatekeydata;
|
||||||
|
privkey_file.passphrase = passphrase;
|
||||||
|
|
||||||
|
if (session->userauth_pblc_state == libssh2_NB_state_idle) {
|
||||||
|
if (publickeydata_len && publickeydata) {
|
||||||
|
rc = memory_read_publickey(session, &session->userauth_pblc_method,
|
||||||
|
&session->userauth_pblc_method_len,
|
||||||
|
&pubkeydata, &pubkeydata_len,
|
||||||
|
publickeydata, publickeydata_len);
|
||||||
|
if(rc)
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
else if (privatekeydata_len && privatekeydata) {
|
||||||
|
/* Compute public key from private key. */
|
||||||
|
if (_libssh2_pub_priv_keyfilememory(session,
|
||||||
|
&session->userauth_pblc_method,
|
||||||
|
&session->userauth_pblc_method_len,
|
||||||
|
&pubkeydata, &pubkeydata_len,
|
||||||
|
privatekeydata, privatekeydata_len,
|
||||||
|
passphrase))
|
||||||
|
return _libssh2_error(session, LIBSSH2_ERROR_FILE,
|
||||||
|
"Unable to extract public key "
|
||||||
|
"from private key.");
|
||||||
|
}
|
||||||
|
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,
|
||||||
|
sign_frommemory, &abstract);
|
||||||
|
if(pubkeydata)
|
||||||
|
LIBSSH2_FREE(session, pubkeydata);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* userauth_publickey_fromfile
|
* userauth_publickey_fromfile
|
||||||
* Authenticate using a keypair found in the named files
|
* Authenticate using a keypair found in the named files
|
||||||
@ -1267,6 +1468,36 @@ userauth_publickey_fromfile(LIBSSH2_SESSION *session,
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* libssh2_userauth_publickey_frommemory
|
||||||
|
* Authenticate using a keypair from memory
|
||||||
|
*/
|
||||||
|
LIBSSH2_API int
|
||||||
|
libssh2_userauth_publickey_frommemory(LIBSSH2_SESSION *session,
|
||||||
|
const char *user,
|
||||||
|
size_t user_len,
|
||||||
|
const char *publickeyfiledata,
|
||||||
|
size_t publickeyfiledata_len,
|
||||||
|
const char *privatekeyfiledata,
|
||||||
|
size_t privatekeyfiledata_len,
|
||||||
|
const char *passphrase)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if(NULL == passphrase)
|
||||||
|
/* if given a NULL pointer, make it point to a zero-length
|
||||||
|
string to save us from having to check this all over */
|
||||||
|
passphrase="";
|
||||||
|
|
||||||
|
BLOCK_ADJUST(rc, session,
|
||||||
|
userauth_publickey_frommemory(session, user, user_len,
|
||||||
|
publickeyfiledata,
|
||||||
|
publickeyfiledata_len,
|
||||||
|
privatekeyfiledata,
|
||||||
|
privatekeyfiledata_len,
|
||||||
|
passphrase));
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
/* libssh2_userauth_publickey_fromfile_ex
|
/* libssh2_userauth_publickey_fromfile_ex
|
||||||
* Authenticate using a keypair found in the named files
|
* Authenticate using a keypair found in the named files
|
||||||
*/
|
*/
|
||||||
|
Загрузка…
x
Ссылка в новой задаче
Block a user